Compare commits
278 Commits
thermion_f
...
thermion_f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59aec2bcc9 | ||
|
|
61d1581b96 | ||
|
|
8e47332ce8 | ||
|
|
ffe8bee98b | ||
|
|
1e07486017 | ||
|
|
58da196876 | ||
|
|
78af155a6d | ||
|
|
d7e1b3d7ba | ||
|
|
877eae35cd | ||
|
|
87846b68de | ||
|
|
6581ee8a2a | ||
|
|
951064e657 | ||
|
|
68ebf945a5 | ||
|
|
153817e859 | ||
|
|
ba0bc54fa7 | ||
|
|
9b99975017 | ||
|
|
e6a6862ba4 | ||
|
|
b7d3e9191a | ||
|
|
b461b2c5db | ||
|
|
8f7f48bcaa | ||
|
|
7dc8e394f7 | ||
|
|
f5c8faa5c3 | ||
|
|
c84b4010d1 | ||
|
|
b720c1294f | ||
|
|
d442ab5ce6 | ||
|
|
61fdf300f4 | ||
|
|
4dabca9160 | ||
|
|
85d6946645 | ||
|
|
4b1d8ce729 | ||
|
|
c52b0084ce | ||
|
|
8db725d8bd | ||
|
|
c67d1cbbc4 | ||
|
|
3ea4062e33 | ||
|
|
65e99b9212 | ||
|
|
e83193ba0d | ||
|
|
835338ef63 | ||
|
|
57872d2e40 | ||
|
|
b5a7996769 | ||
|
|
ddbb4ec5c6 | ||
|
|
7cb3080596 | ||
|
|
f6c91294aa | ||
|
|
412d333525 | ||
|
|
378dede02d | ||
|
|
0e3db2635f | ||
|
|
77147cbafd | ||
|
|
43e5fd7766 | ||
|
|
fc3ca3d6b3 | ||
|
|
51f52bb71b | ||
|
|
033c3f632d | ||
|
|
6d862ef36a | ||
|
|
f816274fb9 | ||
|
|
0816286696 | ||
|
|
b421df5e2f | ||
|
|
f6a136643d | ||
|
|
b5e278183a | ||
|
|
8e85042e37 | ||
|
|
f943756624 | ||
|
|
92814aed56 | ||
|
|
e8a1b976e1 | ||
|
|
ef48dbce30 | ||
|
|
196cc6b980 | ||
|
|
1788c74d4c | ||
|
|
74e808d1dc | ||
|
|
72dacc5b21 | ||
|
|
ebdaf65b89 | ||
|
|
fa43149c98 | ||
|
|
e8ae7193ee | ||
|
|
aa21c0fb76 | ||
|
|
10826466a4 | ||
|
|
3b2d7d8c47 | ||
|
|
212443cb8e | ||
|
|
523141d54b | ||
|
|
d8a0859f16 | ||
|
|
c70cc9abb5 | ||
|
|
66b626e605 | ||
|
|
4b28119318 | ||
|
|
666506aed0 | ||
|
|
a55f63a428 | ||
|
|
fb441e151c | ||
|
|
82d85386c0 | ||
|
|
242b2f6faa | ||
|
|
31d31dd583 | ||
|
|
f6077012b1 | ||
|
|
18bb45dcd8 | ||
|
|
10b919e4f4 | ||
|
|
98cedf821c | ||
|
|
729f72e768 | ||
|
|
d01861e949 | ||
|
|
adec48f253 | ||
|
|
27a8ce18d5 | ||
|
|
4b740a9f5a | ||
|
|
0b34b4546e | ||
|
|
c17919cd97 | ||
|
|
462f1f02bf | ||
|
|
ddc433a126 | ||
|
|
ab649e860d | ||
|
|
676ddc3773 | ||
|
|
7d2cf3f91b | ||
|
|
492d41d756 | ||
|
|
191c2fd709 | ||
|
|
027fc9ae04 | ||
|
|
b73d0e1e96 | ||
|
|
315f2b63b9 | ||
|
|
ad205679cb | ||
|
|
6ef8d19e94 | ||
|
|
6b0f25ca59 | ||
|
|
820d341f67 | ||
|
|
70f904d54c | ||
|
|
aee607908d | ||
|
|
c99c57e24d | ||
|
|
00d75be479 | ||
|
|
3a9bd31919 | ||
|
|
51be1bce39 | ||
|
|
822b8e14c1 | ||
|
|
2ab30a7933 | ||
|
|
1be8a5e862 | ||
|
|
98d61fa1b3 | ||
|
|
5b3d16a316 | ||
|
|
b6863828b4 | ||
|
|
98fefd0e52 | ||
|
|
d476d78e2b | ||
|
|
98113fb79f | ||
|
|
90827ff012 | ||
|
|
44078ba2e0 | ||
|
|
866219ee2e | ||
|
|
d785bd6b7e | ||
|
|
3e4e6653a8 | ||
|
|
8d250e2664 | ||
|
|
d455cea29e | ||
|
|
374e8eb910 | ||
|
|
833fc74b4c | ||
|
|
62417bfebd | ||
|
|
abc9ecbeee | ||
|
|
a1f71ab459 | ||
|
|
d123929fb4 | ||
|
|
141827c59c | ||
|
|
9fbcc9edaf | ||
|
|
83d9c5be30 | ||
|
|
6aadbbc3d0 | ||
|
|
d5bc865cf4 | ||
|
|
d766733489 | ||
|
|
f51c640d17 | ||
|
|
66f10b598a | ||
|
|
59957650aa | ||
|
|
d43fbd8964 | ||
|
|
f5de4349bf | ||
|
|
f67e1a021d | ||
|
|
33f2c5fbf7 | ||
|
|
6a7bde930d | ||
|
|
b827a2142b | ||
|
|
8bd2416bad | ||
|
|
3684eb248c | ||
|
|
9077632d1b | ||
|
|
d40261ae29 | ||
|
|
77dbb574c7 | ||
|
|
89a660144e | ||
|
|
7554af5d41 | ||
|
|
4b742fea2d | ||
|
|
a6c6cff8b6 | ||
|
|
5813753ef9 | ||
|
|
cf0dad2631 | ||
|
|
cfddb99a8b | ||
|
|
845d5bf223 | ||
|
|
dbbd972909 | ||
|
|
aba3ba24af | ||
|
|
81c27dde9f | ||
|
|
476b552fd0 | ||
|
|
5c4d5d4b9d | ||
|
|
ae5ef2c286 | ||
|
|
b0f3c8a087 | ||
|
|
43fc7ffc65 | ||
|
|
ee24fca20e | ||
|
|
a00fdbe042 | ||
|
|
c2eb28a8f5 | ||
|
|
4c6c20f3de | ||
|
|
b2ae8135c6 | ||
|
|
aecde97200 | ||
|
|
331caccc22 | ||
|
|
63e2b74bb1 | ||
|
|
433f03161c | ||
|
|
6ec84b6249 | ||
|
|
29b6a48816 | ||
|
|
00755fd417 | ||
|
|
9c5156e41a | ||
|
|
226c45ee2e | ||
|
|
e04390b2fe | ||
|
|
9a87eb4d9b | ||
|
|
2284d9d081 | ||
|
|
cf61369a8d | ||
|
|
4e14bd2396 | ||
|
|
0798d5c071 | ||
|
|
80d5b1d23f | ||
|
|
0bd87288d1 | ||
|
|
51e06c2eb9 | ||
|
|
b29663923d | ||
|
|
f57a323cda | ||
|
|
03ffe85113 | ||
|
|
4edc8aa85b | ||
|
|
04ecb4d56f | ||
|
|
0ac0a92024 | ||
|
|
ae1e14ddb7 | ||
|
|
aa246ab63a | ||
|
|
d4350d7d99 | ||
|
|
f07fe6084a | ||
|
|
4e29055a20 | ||
|
|
6d0c06a853 | ||
|
|
abe6e1fcb8 | ||
|
|
683105c4f7 | ||
|
|
6f2331582c | ||
|
|
f0f97e310c | ||
|
|
2331f2c31a | ||
|
|
704b7f6734 | ||
|
|
7ac7ae43ab | ||
|
|
d52b23d6b5 | ||
|
|
8b17916cd9 | ||
|
|
4a0f4e3ac8 | ||
|
|
85116f43a2 | ||
|
|
3ecb8920ea | ||
|
|
8923d97129 | ||
|
|
375e1cc887 | ||
|
|
78dcbc8bb9 | ||
|
|
a3f7b98bf7 | ||
|
|
12b61e8767 | ||
|
|
0e3b014c2c | ||
|
|
10db8c39f3 | ||
|
|
371bcb3706 | ||
|
|
714c575409 | ||
|
|
c0941e3b7f | ||
|
|
026acb7467 | ||
|
|
3c05cc6a43 | ||
|
|
f1a2926bdf | ||
|
|
88e8a138ac | ||
|
|
53d0301828 | ||
|
|
b10fec1963 | ||
|
|
08e1eb7778 | ||
|
|
d6713c090c | ||
|
|
497ecbf881 | ||
|
|
6f7d03737e | ||
|
|
ad60c6bbe1 | ||
|
|
92fdda722b | ||
|
|
3cc876f972 | ||
|
|
7d1e706045 | ||
|
|
11756fcedd | ||
|
|
2e1f2cd56d | ||
|
|
c08611b2c3 | ||
|
|
f87f89427d | ||
|
|
c3319ebbf3 | ||
|
|
f7b765c5d0 | ||
|
|
9512b74008 | ||
|
|
5a3517f953 | ||
|
|
731c4981c9 | ||
|
|
8f20a8a859 | ||
|
|
7693a0fe14 | ||
|
|
98c3676fdf | ||
|
|
d7664a9746 | ||
|
|
d868fd6970 | ||
|
|
300396b97e | ||
|
|
1d8faa70a1 | ||
|
|
1051b1bb0e | ||
|
|
c367824041 | ||
|
|
81cedf0d43 | ||
|
|
16c6203b97 | ||
|
|
b7c0eeb7b4 | ||
|
|
fd31b4dcad | ||
|
|
41bf9ededa | ||
|
|
d745712650 | ||
|
|
1df732be7c | ||
|
|
8b413eca52 | ||
|
|
3597077d39 | ||
|
|
7704a06601 | ||
|
|
7b3ad027bf | ||
|
|
cde3af08aa | ||
|
|
7418fb867d | ||
|
|
ce71e09f65 | ||
|
|
5dec13f00b | ||
|
|
7464c05483 | ||
|
|
7b97b2e6c3 | ||
|
|
168f46cf56 |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -153,10 +153,7 @@ thermion_dart/native/lib/ios/libibl-lite.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/ios/libimageio.a filter=lfs diff=lfs merge=lfs -text
|
||||
materials/Makefile filter=lfs diff=lfs merge=lfs -text
|
||||
materials/gizmo.filamat filter=lfs diff=lfs merge=lfs -text
|
||||
materials/gizmo.mat filter=lfs diff=lfs merge=lfs -text
|
||||
materials/image.filamat filter=lfs diff=lfs merge=lfs -text
|
||||
materials/image.mat filter=lfs diff=lfs merge=lfs -text
|
||||
materials/unlit_fade.mat filter=lfs diff=lfs merge=lfs -text
|
||||
materials/unlit_opaque.mat filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/android/arm64-v8a/libktxreader.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/android/armeabi-v7a/libcamutils.a filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
464
CHANGELOG.md
464
CHANGELOG.md
@@ -3,6 +3,470 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0-dev.7.0`](#thermion_dart---v020-dev70)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_flutter_web` - `v0.1.0-dev.7.0`](#thermion_flutter_web---v010-dev70)
|
||||
- [`thermion_flutter` - `v0.2.0-dev.7.0`](#thermion_flutter---v020-dev70)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.7.0`](#thermion_flutter_platform_interface---v020-dev70)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0-dev.7.0`](#thermion_flutter_ffi---v020-dev70)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_web` - `v0.1.0-dev.7.0`
|
||||
- `thermion_flutter` - `v0.2.0-dev.7.0`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.0-dev.7.0`
|
||||
- `thermion_flutter_ffi` - `v0.2.0-dev.7.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0-dev.7.0`
|
||||
|
||||
- **BREAKING** **FIX**: fix min SDK for thermion_dart.
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0-dev.6.0`](#thermion_dart---v020-dev60)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_flutter_web` - `v0.1.0-dev.6.0`](#thermion_flutter_web---v010-dev60)
|
||||
- [`thermion_flutter` - `v0.2.0-dev.6.0`](#thermion_flutter---v020-dev60)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.6.0`](#thermion_flutter_platform_interface---v020-dev60)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0-dev.6.0`](#thermion_flutter_ffi---v020-dev60)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_web` - `v0.1.0-dev.6.0`
|
||||
- `thermion_flutter` - `v0.2.0-dev.6.0`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.0-dev.6.0`
|
||||
- `thermion_flutter_ffi` - `v0.2.0-dev.6.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0-dev.6.0`
|
||||
|
||||
- **BREAKING** **CHORE**: cleanup deleted export.
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_flutter` - `v0.2.0-dev.6.0`](#thermion_flutter---v020-dev60)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- There are no other changes in this release.
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_flutter` - `v0.2.0-dev.6.0`
|
||||
|
||||
- **BREAKING** **CHORE**: remove superseded HardwareKeyboard* classes.
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0-dev.5.0`](#thermion_dart---v020-dev50)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_flutter_web` - `v0.1.0-dev.5.0`](#thermion_flutter_web---v010-dev50)
|
||||
- [`thermion_flutter` - `v0.2.0-dev.5.0`](#thermion_flutter---v020-dev50)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.5.0`](#thermion_flutter_platform_interface---v020-dev50)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0-dev.5.0`](#thermion_flutter_ffi---v020-dev50)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_web` - `v0.1.0-dev.5.0`
|
||||
- `thermion_flutter` - `v0.2.0-dev.5.0`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.0-dev.5.0`
|
||||
- `thermion_flutter_ffi` - `v0.2.0-dev.5.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0-dev.5.0`
|
||||
|
||||
- **BREAKING** **CHORE**: remove EntityTransformController (requires replacement).
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0-dev.4.0`](#thermion_dart---v020-dev40)
|
||||
- [`thermion_flutter_web` - `v0.1.0-dev.4.0`](#thermion_flutter_web---v010-dev40)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_flutter` - `v0.2.0-dev.4.0`](#thermion_flutter---v020-dev40)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.4.0`](#thermion_flutter_platform_interface---v020-dev40)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0-dev.4.0`](#thermion_flutter_ffi---v020-dev40)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter` - `v0.2.0-dev.4.0`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.0-dev.4.0`
|
||||
- `thermion_flutter_ffi` - `v0.2.0-dev.4.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0-dev.4.0`
|
||||
|
||||
- **BREAKING** **FIX**: (web/wasm) free pick callbacks on dispose.
|
||||
- **BREAKING** **CHORE**: restructure viewer folders as libraries to only export the public interface.
|
||||
|
||||
#### `thermion_flutter_web` - `v0.1.0-dev.4.0`
|
||||
|
||||
- **BREAKING** **CHORE**: restructure viewer folders as libraries to only export the public interface.
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_flutter` - `v0.2.0-dev.3.0`](#thermion_flutter---v020-dev30)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- There are no other changes in this release.
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_flutter` - `v0.2.0-dev.3.0`
|
||||
|
||||
- **BREAKING** **FIX**: remove EntityControllerMouseWidget (replace with GestureHandler).
|
||||
- **BREAKING** **CHORE**: (flutter) cleanup for pub.dev publishing.
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_flutter` - `v0.2.0-dev.2.0`](#thermion_flutter---v020-dev20)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- There are no other changes in this release.
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_flutter` - `v0.2.0-dev.2.0`
|
||||
|
||||
- **BREAKING** **CHORE**: remove EntityListWidget - will replace with new Scene.
|
||||
|
||||
|
||||
## 2024-09-25
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0-dev.1.0`](#thermion_dart---v020-dev10)
|
||||
- [`thermion_flutter` - `v0.2.0-dev.1.0`](#thermion_flutter---v020-dev10)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0-dev.1.0`](#thermion_flutter_ffi---v020-dev10)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.1.0`](#thermion_flutter_platform_interface---v020-dev10)
|
||||
- [`thermion_flutter_web` - `v0.1.0-dev.1.0`](#thermion_flutter_web---v010-dev10)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- There are no other changes in this release.
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0-dev.1.0`
|
||||
|
||||
- **REFACTOR**: native types.
|
||||
- **REFACTOR**: native types.
|
||||
- **REFACTOR**: move native types to own header, add methods for create/destroy material instance, add priority/layer to load_glb_from_buffer.
|
||||
- **REFACTOR**: Dart types.
|
||||
- **FIX**: (web) add emscripten guards for flushAndWait call when swapchain destroyed.
|
||||
- **FIX**: ignore pick results directly on axis.
|
||||
- **FIX**: properly destroy entities/material/etc in Gizmo on destruction, remove custom scene creation logic.
|
||||
- **FIX**: add check for nan NDC coordinates for viewport translation.
|
||||
- **FIX**: (wasm) use correct coords for pick, free memory correctly, keep pixelratio copy.
|
||||
- **FIX**: add more nan checks for gizmo manipulation.
|
||||
- **FIX**: emscripten export visibility for add_light.
|
||||
- **FIX**: add Fence to capture() and set stencil buffer by default.
|
||||
- **FEAT**: add removeStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionViewer.
|
||||
- **FEAT**: add removeStencilHighlight, accept color param for setStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionDartApi.
|
||||
- **FEAT**: add flag for keepData for gltf instancing, add highlightScene, add stencilHighlight method.
|
||||
- **FEAT**: grid uses own material.
|
||||
- **FEAT**: parent the cloned entity instance when setting stencil highlight.
|
||||
- **FEAT**: add grid material.
|
||||
- **FEAT**: expose setLightDirection and setLightPosition.
|
||||
- **FEAT**: move HighlightOverlay to nested class, move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector.
|
||||
- **FEAT**: move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector and removeStencilHighlight.
|
||||
- **FEAT**: add setGizmoVisibility/pickGizmo methods to ThermionViewer.
|
||||
- **FEAT**: remove gizmo view references, exclude gizmo entities from picking, add createIbl.
|
||||
- **FEAT**: set stencil highlight on gizmo attach.
|
||||
- **FEAT**: add getAncestor method.
|
||||
- **FEAT**: expose API methods for create_ibl, pick/set gizmo visibility.
|
||||
- **FEAT**: create transparent overlay for gizmo for easier picking.
|
||||
- **FEAT**: rescale gizmo based on distance from camera.
|
||||
- **FEAT**: rescale gizmo based on distance from camera.
|
||||
- **FEAT**: add getAncestor method.
|
||||
- **FEAT**: add startOffset parameter to gltf playAnimation.
|
||||
- **FEAT**: layers, grid.
|
||||
- **FEAT**: layers, grid.
|
||||
- **FEAT**: ignore grid overlay and gizmo center when picking, implement highlighting.
|
||||
- **FEAT**: SceneManager updates (setLayer, add grid, queueRelativePositionUpdateWorld.
|
||||
- **FEAT**: expose set_layer_enabled, get_camera_fov and queue_relative_position_updateg_world_axis to ThermionDartApi.h.
|
||||
- **FEAT**: add getCameraFov to FilamentViewer.
|
||||
- **FEAT**: add new grid overlay files to web CmakeLists.
|
||||
- **FEAT**: re-implement (native) Gizmo class, expose preserveScaling parameter for setParent, add methods for getting viewport bounding box from renderable entity.
|
||||
- **FEAT**: expose setLayerEnabled, viewportDimensions and getCameraFov on ThermionView.
|
||||
- **FEAT**: download WASM module directly on web (no need to embed in index.html any more) and expose updateViewportAndCameraProjection.
|
||||
- **FEAT**: add capture() function and expose viewportDimensions on ThermionViewer (allows easier saving of captured images to PNG).
|
||||
- **FEAT**: (web) allow table growth in emscripten module for passing C-style callback function pointers.
|
||||
- **FEAT**: (web) add capture() method and missing camera navigation controls.
|
||||
- **FEAT**: createIbl.
|
||||
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||
- **BREAKING** **FEAT**: update web/http dependencies.
|
||||
|
||||
#### `thermion_flutter` - `v0.2.0-dev.1.0`
|
||||
|
||||
- **FIX**: (flutter) pass ThermionFlutterOptions to ThermionWidget, use dpr for resizeTexture, delete unnecessary TransparencyPainter class.
|
||||
- **FIX**: (flutter/web) use window.devicePixelRatio for viewport.
|
||||
- **FIX**: (flutter) desktop gesture detector changes for new Gizmo methods.
|
||||
- **FEAT**: allow passing null options to ThermionWidget.
|
||||
- **FEAT**: (flutter) (web) if importCanvasAsWidget is false, render transparency.
|
||||
- **FEAT**: add createViewerWithOptions to ThermionFlutterPlugin and mark createViewer as deprecated.
|
||||
- **FEAT**: add createViewerWithOptions to ThermionFlutterPlugin and mark createViewer as deprecated.
|
||||
- **FEAT**: highlight gizmo on hover.
|
||||
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||
- **BREAKING** **FEAT**: resize canvas on web.
|
||||
- **BREAKING** **CHORE**: rename controller to viewer in gesture detector widgets.
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.2.0-dev.1.0`
|
||||
|
||||
- **FEAT**: (flutter) move DPR calculation to resizeTexture and add createViewerWithOptions method to ThermionFlutterFFI.
|
||||
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||
|
||||
#### `thermion_flutter_platform_interface` - `v0.2.0-dev.1.0`
|
||||
|
||||
- **FEAT**: add createViewerWithOptions to ThermionFlutterPlugin and mark createViewer as deprecated.
|
||||
- **FEAT**: add ThermionFlutterOptions classes, rename interface parameter for offsetTop and ensure pixelRatio is passed to resizeTexture.
|
||||
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||
|
||||
#### `thermion_flutter_web` - `v0.1.0-dev.1.0`
|
||||
|
||||
- **FIX**: (flutter/web) use window.devicePixelRatio for viewport.
|
||||
- **FEAT**: (flutter) (web) use options to determine whether to create canvas, and set fixed position + offset.
|
||||
- **FEAT**: add ThermionFlutterOptions classes, rename interface parameter for offsetTop and ensure pixelRatio is passed to resizeTexture.
|
||||
- **BREAKING** **FEAT**: (flutter) (web) upgrade package:web dep to 1.0.0.
|
||||
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||
- **BREAKING** **FEAT**: resize canvas on web.
|
||||
|
||||
|
||||
## 2024-07-23
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- There are no breaking changes in this release.
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_dart` - `v0.1.3`](#thermion_dart---v013)
|
||||
- [`thermion_flutter_ffi` - `v0.1.0+12`](#thermion_flutter_ffi---v01012)
|
||||
- [`thermion_flutter_web` - `v0.0.3`](#thermion_flutter_web---v003)
|
||||
- [`thermion_flutter_platform_interface` - `v0.1.0+11`](#thermion_flutter_platform_interface---v01011)
|
||||
- [`thermion_flutter` - `v0.1.1+13`](#thermion_flutter---v01113)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_platform_interface` - `v0.1.0+11`
|
||||
- `thermion_flutter` - `v0.1.1+13`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.1.3`
|
||||
|
||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: shadow JS<->WASM bridge methods.
|
||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: shadow JS<->WASM bridge methods.
|
||||
- **FEAT**: add clearMorphAnimationData function.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.1.0+12`
|
||||
|
||||
- **FIX**: add logging dependency.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: add logging dependency.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
|
||||
#### `thermion_flutter_web` - `v0.0.3`
|
||||
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
|
||||
|
||||
## 2024-07-11
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- There are no breaking changes in this release.
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_flutter_ffi` - `v0.1.0+11`](#thermion_flutter_ffi---v01011)
|
||||
- [`thermion_flutter` - `v0.1.1+12`](#thermion_flutter---v01112)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter` - `v0.1.1+12`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.1.0+11`
|
||||
|
||||
- **FIX**: add logging dependency.
|
||||
|
||||
|
||||
## 2024-07-11
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- There are no breaking changes in this release.
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_dart` - `v0.1.2`](#thermion_dart---v012)
|
||||
- [`thermion_flutter_ffi` - `v0.1.0+10`](#thermion_flutter_ffi---v01010)
|
||||
- [`thermion_flutter_web` - `v0.0.2`](#thermion_flutter_web---v002)
|
||||
- [`thermion_flutter` - `v0.1.1+11`](#thermion_flutter---v01111)
|
||||
- [`thermion_flutter_platform_interface` - `v0.1.0+10`](#thermion_flutter_platform_interface---v01010)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter` - `v0.1.1+11`
|
||||
- `thermion_flutter_platform_interface` - `v0.1.0+10`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.1.2`
|
||||
|
||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: shadow JS<->WASM bridge methods.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.1.0+10`
|
||||
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
|
||||
#### `thermion_flutter_web` - `v0.0.2`
|
||||
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
|
||||
|
||||
## 2024-07-04
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- There are no breaking changes in this release.
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_dart` - `v0.1.1+5`](#thermion_dart---v0115)
|
||||
- [`thermion_flutter_web` - `v0.0.1+9`](#thermion_flutter_web---v0019)
|
||||
- [`thermion_flutter` - `v0.1.1+10`](#thermion_flutter---v01110)
|
||||
- [`thermion_flutter_platform_interface` - `v0.1.0+9`](#thermion_flutter_platform_interface---v0109)
|
||||
- [`thermion_flutter_ffi` - `v0.1.0+9`](#thermion_flutter_ffi---v0109)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_web` - `v0.0.1+9`
|
||||
- `thermion_flutter` - `v0.1.1+10`
|
||||
- `thermion_flutter_platform_interface` - `v0.1.0+9`
|
||||
- `thermion_flutter_ffi` - `v0.1.0+9`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.1.1+5`
|
||||
|
||||
- Bump "thermion_dart" to `0.1.1+5`.
|
||||
|
||||
|
||||
## 2024-07-02
|
||||
|
||||
### Changes
|
||||
|
||||
11
Makefile
11
Makefile
@@ -22,10 +22,13 @@ bindings:
|
||||
#
|
||||
materials: FORCE
|
||||
@echo "Using Filament build from ${FILAMENT_PATH}"
|
||||
${FILAMENT_PATH}/matc -a opengl -a metal -o materials/image.filamat materials/image.mat
|
||||
$(FILAMENT_PATH)/resgen -c -p image -x ios/include/material/ materials/image.filamat
|
||||
$(FILAMENT_PATH)/matc -a opengl -a metal -o materials/gizmo.filamat materials/gizmo.mat
|
||||
$(FILAMENT_PATH)/resgen -c -p gizmo -x ios/include/material/ materials/gizmo.filamat
|
||||
@for material in unlit image gizmo grid; do \
|
||||
${FILAMENT_PATH}/matc -a opengl -a metal -o materials/$$material.filamat materials/$$material.mat; \
|
||||
$(FILAMENT_PATH)/resgen -c -p $$material -x thermion_dart/native/include/material/ materials/$$material.filamat; \
|
||||
echo '#include "'$$material'.h"' | cat - thermion_dart/native/include/material/$$material.c > thermion_dart/native/include/material/$$material.c.new; \
|
||||
mv thermion_dart/native/include/material/$$material.c.new thermion_dart/native/include/material/$$material.c; \
|
||||
done
|
||||
|
||||
#rm materials/*.filamat
|
||||
|
||||
FORCE: ;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
],
|
||||
["Misc.", [
|
||||
["Playground", "https://dartpad.thermion.dev"],
|
||||
["Examples", "/examples"],
|
||||
["Showcase", "/showcase"],
|
||||
["Windows", "/windows"],
|
||||
["Android", "/android"],
|
||||
["Contributing", "/contributing"],
|
||||
|
||||
@@ -40,7 +40,7 @@ and change the minimum deployment target to 13.0:
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Click to open Windows instructions">
|
||||
See the [/windows](/Windows) page for steps needed to build on Windows.
|
||||
See the [/windows](/windows) page for steps needed to build on Windows.
|
||||
</Accordion>
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,13 @@ A custom DartPad that lets you experiment with Thermion from your browser (curre
|
||||
|
||||
[](https://dartpad.thermion.dev)
|
||||
|
||||
## mixreel (Flutter/Web)
|
||||
|
||||
Create 3D worlds and translate to AI video.
|
||||
|
||||
[](https://mixreel.ai)
|
||||
|
||||
|
||||
## Nick Fisher
|
||||
|
||||
My personal website, where I create an interactive clone of myself with Avaturn & Cartesia (no Flutter, made with Thermion and the [Jaspr Dart UI framework](https://github.com/schultek/jaspr)).
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:14a484a441dacbc49ce6b8b189a8900a7bb2ab2072731a3a493676aa046b5888
|
||||
size 1009
|
||||
@@ -1,3 +1,50 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3158461d081f058dcb9582ce19cc2daedc73abbe758ba5094c94df89028d8c4d
|
||||
size 981
|
||||
material {
|
||||
name : Gizmo,
|
||||
parameters : [
|
||||
{
|
||||
type : mat4,
|
||||
name : transform,
|
||||
precision : high
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : color,
|
||||
precision : low
|
||||
}
|
||||
],
|
||||
depthWrite : true,
|
||||
depthCulling : false,
|
||||
shadingModel : unlit,
|
||||
blending: transparent,
|
||||
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||
culling: none,
|
||||
instanced: false,
|
||||
vertexDomain: object
|
||||
}
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
|
||||
// we want to ensure the gizmo has the same size (in screen-space), no matter the distance from the camera
|
||||
// we do this by scaling the model-space vertex positions by the distance from the camera
|
||||
vec4 modelSpace = getPosition();
|
||||
vec4 worldSpace = getWorldFromModelMatrix() * modelSpace;
|
||||
vec4 viewSpace = getViewFromWorldMatrix() * worldSpace;
|
||||
float distanceFromCamera = length(viewSpace.xyz);
|
||||
modelSpace.xyz *= (distanceFromCamera / 4.0f); // divide by 4 so that the size is equivalent to the camera being 4 world-space units away from the (unscaled) gizmo
|
||||
|
||||
worldSpace = getWorldFromModelMatrix() * modelSpace;
|
||||
material.worldPosition = worldSpace;
|
||||
//vec4 clipSpace = getClipFromWorldMatrix() * worldSpace;
|
||||
//clipSpace.z = 0.99f;
|
||||
//material.worldPosition = getWorldFromClipMatrix() * clipSpace;
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = materialParams.color;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
53
materials/grid.mat
Normal file
53
materials/grid.mat
Normal file
@@ -0,0 +1,53 @@
|
||||
material {
|
||||
name : Grid,
|
||||
parameters : [
|
||||
{
|
||||
type : float,
|
||||
name : maxDistance
|
||||
},
|
||||
{
|
||||
type : float3,
|
||||
name : color
|
||||
}
|
||||
],
|
||||
depthWrite : true,
|
||||
depthCulling : false,
|
||||
shadingModel : unlit,
|
||||
blending: transparent,
|
||||
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||
culling: none,
|
||||
instanced: false,
|
||||
vertexDomain: object
|
||||
}
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
material.worldPosition = getWorldFromModelMatrix() * getPosition();
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
|
||||
// Convert world position to view space
|
||||
float4 viewPos = getViewFromWorldMatrix() * float4(getWorldPosition(), 1.0);
|
||||
|
||||
// Calculate distance in view space (camera is at 0,0,0 in view space)
|
||||
float distance = length(viewPos.xz);
|
||||
|
||||
// Discard fragment if it's too far from the camera
|
||||
if (distance > materialParams.maxDistance) {
|
||||
material.baseColor = float4(0.0);
|
||||
} else {
|
||||
material.baseColor = float4(materialParams.color, 1.0);
|
||||
|
||||
// Optional: fade out as we approach maxDistance
|
||||
float fadeStart = materialParams.maxDistance * 0.8;
|
||||
if (distance > fadeStart) {
|
||||
float fade = 1.0 - (distance - fadeStart) / (materialParams.maxDistance - fadeStart);
|
||||
material.baseColor.a = fade;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,52 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:273059c97f96c6848807914d937583864445b51d8e0f1cd98c3e4e0e4bd9f411
|
||||
size 1451
|
||||
material {
|
||||
name : Image,
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : image
|
||||
},
|
||||
{
|
||||
type : mat4,
|
||||
name : transform,
|
||||
precision : high
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : backgroundColor
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : showImage
|
||||
}
|
||||
],
|
||||
variables : [
|
||||
imageUV
|
||||
],
|
||||
vertexDomain : device,
|
||||
depthWrite : false,
|
||||
shadingModel : unlit,
|
||||
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||
culling: none
|
||||
}
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
material.imageUV.st = getPosition().st * 0.5 + 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
highp vec2 uv = (materialParams.transform * vec4(saturate(variable_imageUV.st), 1.0, 1.0)).st;
|
||||
if (materialParams.showImage == 0 || uv.s > 1.0 || uv.s < 0.0 || uv.t < 0.0 || uv.t > 1.0) {
|
||||
material.baseColor = materialParams.backgroundColor;
|
||||
} else {
|
||||
uv.t = 1.0 - uv.t;
|
||||
vec4 color = max(texture(materialParams_image, uv.st), 0.0);
|
||||
color.rgb *= color.a;
|
||||
// Manual, pre-multiplied srcOver with opaque destination optimization
|
||||
material.baseColor.rgb = color.rgb + materialParams.backgroundColor.rgb * (1.0 - color.a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
38
materials/unlit.mat
Normal file
38
materials/unlit.mat
Normal file
@@ -0,0 +1,38 @@
|
||||
material {
|
||||
name : unlit,
|
||||
requires : [ uv0 ],
|
||||
parameters : [
|
||||
{
|
||||
type : sampler2d,
|
||||
name : baseColorMap
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : baseColorFactor
|
||||
},
|
||||
{
|
||||
type : int,
|
||||
name : baseColorIndex
|
||||
}
|
||||
],
|
||||
depthWrite : true,
|
||||
depthCulling : true,
|
||||
shadingModel : unlit,
|
||||
blending: opaque,
|
||||
culling: none,
|
||||
instanced: false,
|
||||
vertexDomain: object
|
||||
}
|
||||
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = materialParams.baseColorFactor;
|
||||
|
||||
if (materialParams.baseColorIndex > -1) {
|
||||
highp float2 uv = getUV0();
|
||||
uv.y = 1.0 - uv.y;
|
||||
material.baseColor *= texture(materialParams_baseColorMap, uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4abb9e737d20956cced366af6a54dd31ab17cc8d0d1773f02c57a5712760fe10
|
||||
size 7385
|
||||
@@ -1,3 +1,103 @@
|
||||
## 0.2.0-dev.7.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **BREAKING** **FIX**: fix min SDK for thermion_dart.
|
||||
|
||||
## 0.2.0-dev.6.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **BREAKING** **CHORE**: cleanup deleted export.
|
||||
|
||||
## 0.2.0-dev.5.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **BREAKING** **CHORE**: remove EntityTransformController (requires replacement).
|
||||
|
||||
## 0.2.0-dev.4.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **BREAKING** **FIX**: (web/wasm) free pick callbacks on dispose.
|
||||
- **BREAKING** **CHORE**: restructure viewer folders as libraries to only export the public interface.
|
||||
|
||||
## 0.2.0-dev.1.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **REFACTOR**: native types.
|
||||
- **REFACTOR**: native types.
|
||||
- **REFACTOR**: move native types to own header, add methods for create/destroy material instance, add priority/layer to load_glb_from_buffer.
|
||||
- **REFACTOR**: Dart types.
|
||||
- **FIX**: (web) add emscripten guards for flushAndWait call when swapchain destroyed.
|
||||
- **FIX**: ignore pick results directly on axis.
|
||||
- **FIX**: properly destroy entities/material/etc in Gizmo on destruction, remove custom scene creation logic.
|
||||
- **FIX**: add check for nan NDC coordinates for viewport translation.
|
||||
- **FIX**: (wasm) use correct coords for pick, free memory correctly, keep pixelratio copy.
|
||||
- **FIX**: add more nan checks for gizmo manipulation.
|
||||
- **FIX**: emscripten export visibility for add_light.
|
||||
- **FIX**: add Fence to capture() and set stencil buffer by default.
|
||||
- **FEAT**: add removeStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionViewer.
|
||||
- **FEAT**: add removeStencilHighlight, accept color param for setStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionDartApi.
|
||||
- **FEAT**: add flag for keepData for gltf instancing, add highlightScene, add stencilHighlight method.
|
||||
- **FEAT**: grid uses own material.
|
||||
- **FEAT**: parent the cloned entity instance when setting stencil highlight.
|
||||
- **FEAT**: add grid material.
|
||||
- **FEAT**: expose setLightDirection and setLightPosition.
|
||||
- **FEAT**: move HighlightOverlay to nested class, move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector.
|
||||
- **FEAT**: move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector and removeStencilHighlight.
|
||||
- **FEAT**: add setGizmoVisibility/pickGizmo methods to ThermionViewer.
|
||||
- **FEAT**: remove gizmo view references, exclude gizmo entities from picking, add createIbl.
|
||||
- **FEAT**: set stencil highlight on gizmo attach.
|
||||
- **FEAT**: add getAncestor method.
|
||||
- **FEAT**: expose API methods for create_ibl, pick/set gizmo visibility.
|
||||
- **FEAT**: create transparent overlay for gizmo for easier picking.
|
||||
- **FEAT**: rescale gizmo based on distance from camera.
|
||||
- **FEAT**: rescale gizmo based on distance from camera.
|
||||
- **FEAT**: add getAncestor method.
|
||||
- **FEAT**: add startOffset parameter to gltf playAnimation.
|
||||
- **FEAT**: layers, grid.
|
||||
- **FEAT**: layers, grid.
|
||||
- **FEAT**: ignore grid overlay and gizmo center when picking, implement highlighting.
|
||||
- **FEAT**: SceneManager updates (setLayer, add grid, queueRelativePositionUpdateWorld.
|
||||
- **FEAT**: expose set_layer_enabled, get_camera_fov and queue_relative_position_updateg_world_axis to ThermionDartApi.h.
|
||||
- **FEAT**: add getCameraFov to FilamentViewer.
|
||||
- **FEAT**: add new grid overlay files to web CmakeLists.
|
||||
- **FEAT**: re-implement (native) Gizmo class, expose preserveScaling parameter for setParent, add methods for getting viewport bounding box from renderable entity.
|
||||
- **FEAT**: expose setLayerEnabled, viewportDimensions and getCameraFov on ThermionView.
|
||||
- **FEAT**: download WASM module directly on web (no need to embed in index.html any more) and expose updateViewportAndCameraProjection.
|
||||
- **FEAT**: add capture() function and expose viewportDimensions on ThermionViewer (allows easier saving of captured images to PNG).
|
||||
- **FEAT**: (web) allow table growth in emscripten module for passing C-style callback function pointers.
|
||||
- **FEAT**: (web) add capture() method and missing camera navigation controls.
|
||||
- **FEAT**: createIbl.
|
||||
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||
- **BREAKING** **FEAT**: update web/http dependencies.
|
||||
|
||||
## 0.1.3
|
||||
|
||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: shadow JS<->WASM bridge methods.
|
||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: shadow JS<->WASM bridge methods.
|
||||
- **FEAT**: add clearMorphAnimationData function.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
|
||||
## 0.1.2
|
||||
|
||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||
- **FIX**: web/JS bool checks need to compare to int.
|
||||
- **FIX**: shadow JS<->WASM bridge methods.
|
||||
- **FEAT**: allow passing assetPathPrefix to ThermionViewerWasm to account for Flutter build asset paths.
|
||||
|
||||
## 0.1.1+5
|
||||
|
||||
- Bump "thermion_dart" to `0.1.1+5`.
|
||||
|
||||
## 0.1.1+4
|
||||
|
||||
- **FIX**: defer creating image entity/material/etc until actually requested.
|
||||
|
||||
1
thermion_dart/example/README.md
Normal file
1
thermion_dart/example/README.md
Normal file
@@ -0,0 +1 @@
|
||||
For an example with both pure Dart and Flutter, see the [example repository](https://github.com/nmfisher/thermion_examples).
|
||||
@@ -1,13 +1,19 @@
|
||||
output: '../lib/thermion_dart/compatibility/native/thermion_dart.g.dart'
|
||||
output: '../lib/thermion_dart/viewer/ffi/thermion_dart.g.dart'
|
||||
headers:
|
||||
entry-points:
|
||||
- '../native/include/ThermionDartFFIApi.h'
|
||||
- '../native/include/ThermionDartRenderThreadApi.h'
|
||||
- '../native/include/ThermionDartApi.h'
|
||||
- '../native/include/ResourceBuffer.h'
|
||||
include-directives:
|
||||
- '../native/include/ThermionDartFFIApi.h'
|
||||
- '../native/include/ThermionDartRenderThreadApi.h'
|
||||
- '../native/include/ThermionDartApi.h'
|
||||
- '../native/include/ResourceBuffer.h'
|
||||
- '../native/include/APIBoundaryTypes.h'
|
||||
ffi-native:
|
||||
assetId: package:thermion_dart/thermion_dart.dart
|
||||
ignore-source-errors: true
|
||||
functions:
|
||||
leaf:
|
||||
include:
|
||||
- '.*'
|
||||
|
||||
|
||||
@@ -60,6 +60,8 @@ void main(List<String> args) async {
|
||||
sources.addAll([
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/gizmo.c",
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/image.c",
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/grid.c",
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/unlit.c",
|
||||
]);
|
||||
|
||||
var libs = [
|
||||
@@ -76,7 +78,6 @@ void main(List<String> args) async {
|
||||
"image",
|
||||
"imageio",
|
||||
"tinyexr",
|
||||
"gltfio_core",
|
||||
"filaflat",
|
||||
"dracodec",
|
||||
"ibl",
|
||||
@@ -176,9 +177,17 @@ void main(List<String> args) async {
|
||||
Architecture.ia32 => "i686-linux-android",
|
||||
_ => throw FormatException('Invalid')
|
||||
};
|
||||
var ndkRoot = File(config.cCompiler.compiler!.path).parent.parent.path;
|
||||
|
||||
var compilerPath = config.cCompiler.compiler!.path;
|
||||
|
||||
if(Platform.isWindows && compilerPath.startsWith("/")) {
|
||||
compilerPath = compilerPath.substring(1);
|
||||
}
|
||||
|
||||
var ndkRoot = File(compilerPath).parent.parent.uri.toFilePath(windows:true);
|
||||
|
||||
var stlPath =
|
||||
File("$ndkRoot/sysroot/usr/lib/${archExtension}/libc++_shared.so");
|
||||
File([ndkRoot, "sysroot", "usr", "lib", archExtension, "libc++_shared.so"].join(Platform.pathSeparator));
|
||||
output.addAsset(NativeCodeAsset(
|
||||
package: "thermion_dart",
|
||||
name: "libc++_shared.so",
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
library filament_dart;
|
||||
|
||||
export 'thermion_dart/thermion_viewer.dart';
|
||||
export 'thermion_dart/thermion_viewer_stub.dart'
|
||||
if (dart.library.io) 'thermion_dart/thermion_viewer_ffi.dart'
|
||||
if (dart.library.js_interop)'thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart';
|
||||
|
||||
export 'thermion_dart/entities/entity_transform_controller.dart';
|
||||
export 'thermion_dart/utils/geometry.dart';
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export 'native/compatibility.dart';
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
||||
import 'dart:ffi';
|
||||
export "allocator.dart";
|
||||
export "thermion_dart.g.dart";
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:ffi' as ffi hide Uint8Pointer, FloatPointer;
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart/compatibility/web/ffi/thermion_dart.g.dart';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer;
|
||||
export 'dart:ffi'
|
||||
hide
|
||||
Uint8Pointer,
|
||||
FloatPointer,
|
||||
DoublePointer,
|
||||
Int32Pointer,
|
||||
Int64Pointer,
|
||||
PointerPointer,
|
||||
Allocator;
|
||||
|
||||
class Allocator implements ffi.Allocator {
|
||||
const Allocator();
|
||||
@override
|
||||
ffi.Pointer<T> allocate<T extends ffi.NativeType>(int byteCount,
|
||||
{int? alignment}) {
|
||||
return thermion_flutter_web_allocate(byteCount).cast<T>();
|
||||
}
|
||||
|
||||
@override
|
||||
void free(ffi.Pointer<ffi.NativeType> pointer) {
|
||||
thermion_flutter_web_free(pointer.cast<ffi.Void>());
|
||||
}
|
||||
}
|
||||
|
||||
extension CharPointer on ffi.Pointer<ffi.Char> {
|
||||
int get value {
|
||||
return thermion_flutter_web_get(this, 0);
|
||||
}
|
||||
|
||||
set value(int value) {
|
||||
thermion_flutter_web_set(this, 0, value);
|
||||
}
|
||||
|
||||
void operator []=(int index, int value) {
|
||||
this.elementAt(index).value = value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Char> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Char>() * index);
|
||||
}
|
||||
|
||||
extension IntPointer on ffi.Pointer<ffi.Int> {
|
||||
int get value {
|
||||
return thermion_flutter_web_get_int32(this.cast<ffi.Int32>(), 0);
|
||||
}
|
||||
|
||||
set value(int value) {
|
||||
thermion_flutter_web_set_int32(this.cast<ffi.Int32>(), 0, value);
|
||||
}
|
||||
|
||||
void operator []=(int index, int value) {
|
||||
this.elementAt(index).value = value;
|
||||
}
|
||||
|
||||
int operator [](int index) {
|
||||
return this.elementAt(index).value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Int> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Int>() * index);
|
||||
}
|
||||
|
||||
extension Int32Pointer on ffi.Pointer<ffi.Int32> {
|
||||
int get value {
|
||||
return thermion_flutter_web_get_int32(this, 0);
|
||||
}
|
||||
|
||||
set value(int value) {
|
||||
thermion_flutter_web_set_int32(this, 0, value);
|
||||
}
|
||||
|
||||
void operator []=(int index, int value) {
|
||||
this.elementAt(index).value = value;
|
||||
}
|
||||
|
||||
int operator [](int index) {
|
||||
return this.elementAt(index).value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Int32> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Int32>() * index);
|
||||
}
|
||||
|
||||
extension UInt8Pointer on ffi.Pointer<ffi.Uint8> {
|
||||
int get value {
|
||||
return thermion_flutter_web_get(this.cast<ffi.Char>(), 0);
|
||||
}
|
||||
|
||||
set value(int value) {
|
||||
thermion_flutter_web_set(this.cast<ffi.Char>(), 0, value);
|
||||
}
|
||||
|
||||
void operator []=(int index, int value) {
|
||||
this.elementAt(index).value = value;
|
||||
}
|
||||
|
||||
int operator [](int index) {
|
||||
return this.elementAt(index).value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Uint8> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Uint8>() * index);
|
||||
}
|
||||
|
||||
extension PointerPointer<T extends ffi.NativeType>
|
||||
on ffi.Pointer<ffi.Pointer<T>> {
|
||||
ffi.Pointer<T> get value {
|
||||
return thermion_flutter_web_get_pointer(cast<ffi.Pointer<ffi.Void>>(), 0)
|
||||
.cast<T>();
|
||||
}
|
||||
|
||||
set value(ffi.Pointer<T> value) {
|
||||
thermion_flutter_web_set_pointer(
|
||||
cast<ffi.Pointer<ffi.Void>>(), 0, value.cast<ffi.Void>());
|
||||
}
|
||||
|
||||
|
||||
ffi.Pointer<T> operator [](int index) {
|
||||
return this.elementAt(index).value;
|
||||
}
|
||||
|
||||
void operator []=(int index, ffi.Pointer<T> value) {
|
||||
this.elementAt(index).value = value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Pointer<T>> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Pointer>() * index);
|
||||
}
|
||||
|
||||
extension FloatPointer on ffi.Pointer<ffi.Float> {
|
||||
double get value {
|
||||
return thermion_flutter_web_get_float(this, 0);
|
||||
}
|
||||
|
||||
set value(double value) {
|
||||
thermion_flutter_web_set_float(this, 0, value);
|
||||
}
|
||||
|
||||
double operator [](int index) {
|
||||
return this.elementAt(index).value;
|
||||
}
|
||||
|
||||
void operator []=(int index, double value) {
|
||||
this.elementAt(index).value = value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Float> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Float>() * index);
|
||||
|
||||
Float32List asTypedList(int length) {
|
||||
var list = Float32List(length);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
list[i] = this[i];
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
extension StringConversion on String {
|
||||
ffi.Pointer<Utf8> toNativeUtf8({ffi.Allocator? allocator}) {
|
||||
final units = utf8.encode(this);
|
||||
final ffi.Pointer<ffi.Uint8> result =
|
||||
allocator!<ffi.Uint8>(units.length + 1);
|
||||
for (int i = 0; i < units.length; i++) {
|
||||
result.elementAt(i).value = units[i];
|
||||
}
|
||||
result.elementAt(units.length).value = 0;
|
||||
return result.cast();
|
||||
}
|
||||
}
|
||||
|
||||
extension StringUtf8Pointer on ffi.Pointer<Utf8> {
|
||||
static int _length(ffi.Pointer<ffi.Uint8> codeUnits) {
|
||||
var length = 0;
|
||||
while (codeUnits[length] != 0) {
|
||||
length++;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
String toDartString({int? length}) {
|
||||
final codeUnits = this.cast<ffi.Uint8>();
|
||||
final list = <int>[];
|
||||
|
||||
if (length != null) {
|
||||
RangeError.checkNotNegative(length, 'length');
|
||||
} else {
|
||||
length = _length(codeUnits);
|
||||
}
|
||||
for (int i = 0; i < length; i++) {
|
||||
list.add(codeUnits.elementAt(i).value);
|
||||
}
|
||||
return utf8.decode(list);
|
||||
}
|
||||
}
|
||||
|
||||
extension DoublePointer on ffi.Pointer<ffi.Double> {
|
||||
double get value {
|
||||
return thermion_flutter_web_get_double(this, 0);
|
||||
}
|
||||
|
||||
set value(double value) {
|
||||
return thermion_flutter_web_set_double(this, 0, value);
|
||||
}
|
||||
|
||||
Float64List asTypedList(int length) {
|
||||
var list = Float64List(length);
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
list[i] = elementAt(i).value;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
double operator [](int index) {
|
||||
return elementAt(index).value;
|
||||
}
|
||||
|
||||
void operator []=(int index, double value) {
|
||||
elementAt(index).value = value;
|
||||
}
|
||||
|
||||
ffi.Pointer<ffi.Double> elementAt(int index) =>
|
||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Double>() * index);
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:js_interop';
|
||||
import 'package:thermion_dart/thermion_dart/compatibility/web/ffi/interop.dart';
|
||||
|
||||
import "allocator.dart";
|
||||
|
||||
export "allocator.dart";
|
||||
export "thermion_dart.g.dart";
|
||||
|
||||
export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer;
|
||||
export 'dart:ffi'
|
||||
hide
|
||||
Uint8Pointer,
|
||||
FloatPointer,
|
||||
DoublePointer,
|
||||
Int32Pointer,
|
||||
Int64Pointer,
|
||||
PointerPointer,
|
||||
Allocator;
|
||||
|
||||
const allocator = Allocator();
|
||||
|
||||
@AbiSpecificIntegerMapping({
|
||||
Abi.androidArm: Uint8(),
|
||||
Abi.androidArm64: Uint8(),
|
||||
Abi.androidIA32: Int8(),
|
||||
Abi.androidX64: Int8(),
|
||||
Abi.androidRiscv64: Uint8(),
|
||||
Abi.fuchsiaArm64: Uint8(),
|
||||
Abi.fuchsiaX64: Int8(),
|
||||
Abi.fuchsiaRiscv64: Uint8(),
|
||||
Abi.iosArm: Int8(),
|
||||
Abi.iosArm64: Int8(),
|
||||
Abi.iosX64: Int8(),
|
||||
Abi.linuxArm: Uint8(),
|
||||
Abi.linuxArm64: Uint8(),
|
||||
Abi.linuxIA32: Int8(),
|
||||
Abi.linuxX64: Int8(),
|
||||
Abi.linuxRiscv32: Uint8(),
|
||||
Abi.linuxRiscv64: Uint8(),
|
||||
Abi.macosArm64: Int8(),
|
||||
Abi.macosX64: Int8(),
|
||||
Abi.windowsArm64: Int8(),
|
||||
Abi.windowsIA32: Int8(),
|
||||
Abi.windowsX64: Int8(),
|
||||
})
|
||||
final class FooChar extends AbiSpecificInteger {
|
||||
const FooChar();
|
||||
}
|
||||
|
||||
class Compatibility {
|
||||
final _foo = FooChar();
|
||||
}
|
||||
|
||||
Future<void> withVoidCallback(
|
||||
Function(Pointer<NativeFunction<Void Function()>>) func) async {
|
||||
JSArray retVal = createVoidCallback();
|
||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
||||
var fnPtr = Pointer<NativeFunction<Void Function()>>.fromAddress(
|
||||
fnPtrAddress.toDartInt);
|
||||
func(fnPtr);
|
||||
await promise.toDart;
|
||||
}
|
||||
|
||||
Future<int> withVoidPointerCallback(
|
||||
void Function(Pointer<NativeFunction<Void Function(Pointer<Void>)>>)
|
||||
func) async {
|
||||
JSArray retVal = createVoidPointerCallback();
|
||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
||||
|
||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
||||
var fnPtr = Pointer<NativeFunction<Void Function(Pointer<Void>)>>.fromAddress(
|
||||
fnPtrAddress.toDartInt);
|
||||
func(fnPtr);
|
||||
final addr = await promise.toDart;
|
||||
return addr.toDartInt;
|
||||
}
|
||||
|
||||
Future<bool> withBoolCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Bool)>>) func) async {
|
||||
JSArray retVal = createBoolCallback();
|
||||
var promise = retVal.toDart[0] as JSPromise<JSBoolean>;
|
||||
|
||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
||||
var fnPtr = Pointer<NativeFunction<Void Function(Bool)>>.fromAddress(
|
||||
fnPtrAddress.toDartInt);
|
||||
func(fnPtr);
|
||||
final addr = await promise.toDart;
|
||||
return addr.toDart;
|
||||
}
|
||||
|
||||
Future<int> withIntCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Int32)>>) func) async {
|
||||
JSArray retVal = createBoolCallback();
|
||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
||||
|
||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
||||
var fnPtr = Pointer<NativeFunction<Void Function(Int32)>>.fromAddress(
|
||||
fnPtrAddress.toDartInt);
|
||||
func(fnPtr);
|
||||
final addr = await promise.toDart;
|
||||
return addr.toDartInt;
|
||||
}
|
||||
|
||||
Future<String> withCharPtrCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Pointer<Char>)>>)
|
||||
func) async {
|
||||
JSArray retVal = createVoidPointerCallback();
|
||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
||||
|
||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
||||
var fnPtr = Pointer<NativeFunction<Void Function(Pointer<Char>)>>.fromAddress(
|
||||
fnPtrAddress.toDartInt);
|
||||
func(fnPtr);
|
||||
final addr = await promise.toDart;
|
||||
return Pointer<Utf8>.fromAddress(addr.toDartInt).toDartString();
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import 'dart:js_interop';
|
||||
|
||||
@JS()
|
||||
external JSArray createIntCallback();
|
||||
|
||||
@JS()
|
||||
external JSArray createBoolCallback();
|
||||
|
||||
@JS()
|
||||
external JSArray createVoidPointerCallback();
|
||||
|
||||
@JS()
|
||||
external JSArray createVoidCallback();
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,20 @@
|
||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
abstract class AbstractGizmo {
|
||||
|
||||
bool get isVisible;
|
||||
bool get isHovered;
|
||||
|
||||
Future translate(double transX, double transY);
|
||||
|
||||
void reset();
|
||||
|
||||
Future attach(ThermionEntity entity);
|
||||
|
||||
Future detach();
|
||||
|
||||
Stream<Aabb2> get boundingBox;
|
||||
|
||||
void checkHover(double x, double y);
|
||||
}
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||
import 'package:vector_math/vector_math_64.dart' as v;
|
||||
|
||||
class EntityTransformController {
|
||||
final ThermionViewer controller;
|
||||
final ThermionEntity _entity;
|
||||
|
||||
late Timer _ticker;
|
||||
|
||||
double translationSpeed;
|
||||
double rotationRadsPerSecond;
|
||||
|
||||
bool _forward = false;
|
||||
bool _strafeLeft = false;
|
||||
bool _strafeRight = false;
|
||||
bool _back = false;
|
||||
bool _rotateLeft = false;
|
||||
bool _rotateRight = false;
|
||||
double _rotY = 0;
|
||||
|
||||
int? forwardAnimationIndex;
|
||||
int? backwardAnimationIndex;
|
||||
int? strafeLeftAnimationIndex;
|
||||
int? strafeRightAnimationIndex;
|
||||
|
||||
EntityTransformController(this.controller, this._entity,
|
||||
{this.translationSpeed = 1,
|
||||
this.rotationRadsPerSecond = pi / 2,
|
||||
this.forwardAnimationIndex,
|
||||
this.backwardAnimationIndex,
|
||||
this.strafeLeftAnimationIndex,
|
||||
this.strafeRightAnimationIndex}) {
|
||||
var translationSpeedPerTick = translationSpeed / (1000 / 16.667);
|
||||
var rotationRadsPerTick = rotationRadsPerSecond / (1000 / 16.667);
|
||||
_ticker = Timer.periodic(const Duration(milliseconds: 16), (timer) {
|
||||
_update(translationSpeedPerTick, rotationRadsPerTick);
|
||||
});
|
||||
}
|
||||
|
||||
bool _enabled = true;
|
||||
void enable() {
|
||||
_enabled = true;
|
||||
}
|
||||
|
||||
void disable() {
|
||||
_enabled = false;
|
||||
}
|
||||
|
||||
void _update(
|
||||
double translationSpeedPerTick, double rotationRadsPerTick) async {
|
||||
if (!_enabled) {
|
||||
return;
|
||||
}
|
||||
var _position = v.Vector3.zero();
|
||||
bool updateTranslation = false;
|
||||
if (_forward) {
|
||||
_position.add(v.Vector3(0, 0, -translationSpeedPerTick));
|
||||
updateTranslation = true;
|
||||
}
|
||||
if (_back) {
|
||||
_position.add(v.Vector3(0, 0, translationSpeedPerTick));
|
||||
updateTranslation = true;
|
||||
}
|
||||
if (_strafeLeft) {
|
||||
_position.add(v.Vector3(-translationSpeedPerTick, 0, 0));
|
||||
updateTranslation = true;
|
||||
}
|
||||
if (_strafeRight) {
|
||||
_position.add(v.Vector3(translationSpeedPerTick, 0, 0));
|
||||
updateTranslation = true;
|
||||
}
|
||||
|
||||
// TODO - use pitch/yaw/roll
|
||||
bool updateRotation = false;
|
||||
var _rotation = v.Quaternion.identity();
|
||||
|
||||
double rads = 0.0;
|
||||
if (_rotY != 0) {
|
||||
rads = _rotY * pi / 1000;
|
||||
var rotY = v.Quaternion.axisAngle(v.Vector3(0, 1, 0), rads).normalized();
|
||||
_rotation = rotY;
|
||||
updateRotation = true;
|
||||
_rotY = 0;
|
||||
}
|
||||
|
||||
if (updateTranslation) {
|
||||
await controller.queuePositionUpdate(
|
||||
_entity, _position.x, _position.y, _position.z,
|
||||
relative: true);
|
||||
}
|
||||
if (updateRotation) {
|
||||
await controller.queueRotationUpdateQuat(_entity, _rotation,
|
||||
relative: true);
|
||||
}
|
||||
}
|
||||
|
||||
void look(double deltaX) async {
|
||||
_rotY -= deltaX;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_ticker.cancel();
|
||||
}
|
||||
|
||||
bool _playingForwardAnimation = false;
|
||||
bool _playingBackwardAnimation = false;
|
||||
|
||||
void forwardPressed() async {
|
||||
_forward = true;
|
||||
if (forwardAnimationIndex != null && !_playingForwardAnimation) {
|
||||
await controller.playAnimation(_entity, forwardAnimationIndex!,
|
||||
loop: true, replaceActive: false);
|
||||
_playingForwardAnimation = true;
|
||||
}
|
||||
}
|
||||
|
||||
void forwardReleased() async {
|
||||
_forward = false;
|
||||
await Future.delayed(Duration(milliseconds: 50));
|
||||
if (!_forward) {
|
||||
_playingForwardAnimation = false;
|
||||
if (forwardAnimationIndex != null) {
|
||||
await controller.stopAnimation(_entity, forwardAnimationIndex!);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void backPressed() async {
|
||||
_back = true;
|
||||
if (forwardAnimationIndex != null) {
|
||||
if (!_playingBackwardAnimation) {
|
||||
await controller.playAnimation(_entity, forwardAnimationIndex!,
|
||||
loop: true, replaceActive: false, reverse: true);
|
||||
_playingBackwardAnimation = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void backReleased() async {
|
||||
_back = false;
|
||||
if (forwardAnimationIndex != null) {
|
||||
await controller.stopAnimation(_entity, forwardAnimationIndex!);
|
||||
}
|
||||
_playingBackwardAnimation = false;
|
||||
}
|
||||
|
||||
void strafeLeftPressed() {
|
||||
_strafeLeft = true;
|
||||
}
|
||||
|
||||
void strafeLeftReleased() async {
|
||||
_strafeLeft = false;
|
||||
}
|
||||
|
||||
void strafeRightPressed() {
|
||||
_strafeRight = true;
|
||||
}
|
||||
|
||||
void strafeRightReleased() async {
|
||||
_strafeRight = false;
|
||||
}
|
||||
|
||||
void Function()? _mouse1DownCallback;
|
||||
void onMouse1Down(void Function() callback) {
|
||||
_mouse1DownCallback = callback;
|
||||
}
|
||||
|
||||
void mouse1Down() async {
|
||||
_mouse1DownCallback?.call();
|
||||
}
|
||||
|
||||
void mouse1Up() async {}
|
||||
|
||||
void mouse2Up() async {}
|
||||
|
||||
void mouse2Down() async {}
|
||||
}
|
||||
@@ -1,46 +1,68 @@
|
||||
|
||||
import 'dart:async';
|
||||
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import '../thermion_viewer.dart';
|
||||
|
||||
class Gizmo extends AbstractGizmo {
|
||||
final ThermionEntity x;
|
||||
Vector3 _x = Vector3(0.1, 0, 0);
|
||||
final ThermionEntity y;
|
||||
Vector3 _y = Vector3(0.0, 0.1, 0);
|
||||
final ThermionEntity z;
|
||||
Vector3 _z = Vector3(0.0, 0.0, 0.1);
|
||||
final ThermionEntity center;
|
||||
|
||||
final ThermionViewer controller;
|
||||
final ThermionViewer _viewer;
|
||||
|
||||
ThermionEntity? _activeAxis;
|
||||
ThermionEntity? _activeEntity;
|
||||
bool get isActive => _activeAxis != null;
|
||||
|
||||
bool _visible = false;
|
||||
bool get isVisible => _visible;
|
||||
|
||||
bool _isHovered = false;
|
||||
bool get isHovered => _isHovered;
|
||||
|
||||
final Set<ThermionEntity> ignore;
|
||||
|
||||
Gizmo(this.x, this.y, this.z, this.controller,
|
||||
Stream<Aabb2> get boundingBox => _boundingBoxController.stream;
|
||||
final _boundingBoxController = StreamController<Aabb2>.broadcast();
|
||||
|
||||
Gizmo(this.x, this.y, this.z, this.center, this._viewer,
|
||||
{this.ignore = const <ThermionEntity>{}}) {
|
||||
controller.pickResult.listen(_onPickResult);
|
||||
_viewer.gizmoPickResult.listen(_onGizmoPickResult);
|
||||
_viewer.pickResult.listen(_onPickResult);
|
||||
}
|
||||
|
||||
Future _reveal() async {
|
||||
await controller.reveal(x, null);
|
||||
await controller.reveal(y, null);
|
||||
await controller.reveal(z, null);
|
||||
}
|
||||
final _stopwatch = Stopwatch();
|
||||
|
||||
void translate(double transX, double transY) async {
|
||||
late Vector3 vec;
|
||||
if (_activeAxis == x) {
|
||||
vec = _x;
|
||||
} else if (_activeAxis == y) {
|
||||
vec = _y;
|
||||
} else if (_activeAxis == z) {
|
||||
vec = _z;
|
||||
double _transX = 0.0;
|
||||
double _transY = 0.0;
|
||||
|
||||
Future translate(double transX, double transY) async {
|
||||
if (!_stopwatch.isRunning) {
|
||||
_stopwatch.start();
|
||||
}
|
||||
await controller.queuePositionUpdate(
|
||||
_activeEntity!, transX * vec.x, -transY * vec.y, -transX * vec.z,
|
||||
relative: true);
|
||||
|
||||
_transX += transX;
|
||||
_transY += transY;
|
||||
|
||||
if (_stopwatch.elapsedMilliseconds < 16) {
|
||||
return;
|
||||
}
|
||||
|
||||
final axis = Vector3(_activeAxis == x ? 1.0 : 0.0,
|
||||
_activeAxis == y ? 1.0 : 0.0, _activeAxis == z ? 1.0 : 0.0);
|
||||
|
||||
await _viewer.queueRelativePositionUpdateWorldAxis(
|
||||
_activeEntity!,
|
||||
_transX * _viewer.pixelRatio,
|
||||
-_transY *
|
||||
_viewer
|
||||
.pixelRatio, // flip the sign because "up" in NDC Y axis is positive, but negative in Flutter
|
||||
axis.x,
|
||||
axis.y,
|
||||
axis.z);
|
||||
_transX = 0;
|
||||
_transY = 0;
|
||||
_stopwatch.reset();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
@@ -48,32 +70,48 @@ class Gizmo extends AbstractGizmo {
|
||||
}
|
||||
|
||||
void _onPickResult(FilamentPickResult result) async {
|
||||
if (ignore.contains(result)) {
|
||||
detach();
|
||||
return;
|
||||
}
|
||||
await attach(result.entity);
|
||||
}
|
||||
|
||||
void _onGizmoPickResult(FilamentPickResult result) async {
|
||||
if (result.entity == x || result.entity == y || result.entity == z) {
|
||||
_activeAxis = result.entity;
|
||||
_isHovered = true;
|
||||
} else if (result.entity == 0) {
|
||||
_activeAxis = null;
|
||||
_isHovered = false;
|
||||
} else {
|
||||
attach(result.entity);
|
||||
throw Exception("Unexpected gizmo pick result");
|
||||
}
|
||||
}
|
||||
|
||||
void attach(ThermionEntity entity) async {
|
||||
Future attach(ThermionEntity entity) async {
|
||||
_activeAxis = null;
|
||||
if (entity == _activeEntity) {
|
||||
return;
|
||||
}
|
||||
if (entity == center) {
|
||||
_activeEntity = null;
|
||||
return;
|
||||
}
|
||||
_visible = true;
|
||||
|
||||
if (_activeEntity != null) {
|
||||
await _viewer.removeStencilHighlight(_activeEntity!);
|
||||
}
|
||||
_activeEntity = entity;
|
||||
await _reveal();
|
||||
await controller.setParent(x, entity);
|
||||
await controller.setParent(y, entity);
|
||||
await controller.setParent(z, entity);
|
||||
await _viewer.setGizmoVisibility(true);
|
||||
await _viewer.setParent(center, entity, preserveScaling: false);
|
||||
_boundingBoxController.sink.add(await _viewer.getViewportBoundingBox(x));
|
||||
|
||||
}
|
||||
|
||||
void detach() async {
|
||||
await controller.setParent(x, 0);
|
||||
await controller.setParent(y, 0);
|
||||
await controller.setParent(z, 0);
|
||||
await controller.hide(x, null);
|
||||
await controller.hide(y, null);
|
||||
await controller.hide(z, null);
|
||||
Future detach() async {
|
||||
await _viewer.setGizmoVisibility(false);
|
||||
}
|
||||
|
||||
@override
|
||||
void checkHover(double x, double y) {
|
||||
_viewer.pickGizmo(x.toInt(), y.toInt());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,48 +1,233 @@
|
||||
import 'dart:convert';
|
||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||
import 'dart:async';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
///
|
||||
/// For now, this class just holds the entities that have been loaded (though not necessarily visible in the Filament Scene).
|
||||
///
|
||||
abstract class Scene {
|
||||
///
|
||||
/// The last entity clicked/tapped in the viewport (internally, the result of calling pick);
|
||||
ThermionEntity? selected;
|
||||
class SceneV2 {
|
||||
final Map<String, AssetInfo> assets;
|
||||
final List<LightInfo> lights;
|
||||
List<CameraInfo> cameras;
|
||||
final List<EntityInfo> entities;
|
||||
EnvironmentInfo? environment;
|
||||
|
||||
///
|
||||
/// A Stream updated whenever an entity is added/removed from the scene.
|
||||
///
|
||||
Stream<bool> get onUpdated;
|
||||
SceneV2({
|
||||
Map<String, AssetInfo>? assets,
|
||||
List<LightInfo>? lights,
|
||||
List<CameraInfo>? cameras,
|
||||
List<EntityInfo>? entities,
|
||||
this.environment,
|
||||
}) : assets = assets ?? {},
|
||||
lights = lights ?? [],
|
||||
cameras = cameras ?? [],
|
||||
entities = entities ?? [];
|
||||
|
||||
///
|
||||
/// A Stream containing every ThermionEntity added to the scene (i.e. via [loadGlb], [loadGltf] or [addLight]).
|
||||
/// This is provided for convenience so you can set listeners in front-end widgets that can respond to entity loads without manually passing around the ThermionEntity returned from those methods.
|
||||
///
|
||||
Stream<ThermionEntity> get onLoad;
|
||||
void addAsset(String uri, AssetType type) {
|
||||
assets[uri] = AssetInfo(uri: uri, type: type);
|
||||
}
|
||||
|
||||
///
|
||||
/// A Stream containing every ThermionEntity removed from the scene (i.e. via [removeEntity], [clearEntities], [removeLight] or [clearLights]).
|
||||
void addLight(LightInfo light) {
|
||||
lights.add(light);
|
||||
}
|
||||
|
||||
Stream<ThermionEntity> get onUnload;
|
||||
void clearAssets() {
|
||||
assets.clear();
|
||||
}
|
||||
|
||||
///
|
||||
/// Lists all light entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
||||
///
|
||||
Iterable<ThermionEntity> listLights();
|
||||
void clearLights() {
|
||||
lights.clear();
|
||||
}
|
||||
|
||||
///
|
||||
/// Lists all entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
||||
///
|
||||
Iterable<ThermionEntity> listEntities();
|
||||
void setCamera(Matrix4 modelMatrix, Matrix4 projectionMatrix) {
|
||||
var camera = cameras.firstWhere((cam) => cam.isActive);
|
||||
camera.modelMatrix = modelMatrix;
|
||||
camera.projectionMatrix = projectionMatrix;
|
||||
}
|
||||
|
||||
///
|
||||
/// Attach the gizmo to the specified entity.
|
||||
///
|
||||
void select(ThermionEntity entity);
|
||||
void addEntity(String assetUri, Matrix4 transform) {
|
||||
if (assets.containsKey(assetUri)) {
|
||||
entities.add(EntityInfo(assetUri: assetUri, transform: transform));
|
||||
} else {
|
||||
throw Exception('Asset not found: $assetUri');
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
void registerEntity(ThermionEntity entity);
|
||||
void setEnvironment(String? skyboxUri, String? iblUri) {
|
||||
environment = EnvironmentInfo(skyboxUri: skyboxUri, iblUri: iblUri);
|
||||
}
|
||||
|
||||
}
|
||||
Map<String, dynamic> toJson() => {
|
||||
'assets': assets.map((key, value) => MapEntry(key, value.toJson())),
|
||||
'lights': lights.map((light) => light.toJson()).toList(),
|
||||
'cameras': cameras.map((camera) => camera.toJson()),
|
||||
'entities': entities.map((entity) => entity.toJson()).toList(),
|
||||
'environment': environment?.toJson(),
|
||||
};
|
||||
|
||||
String toJsonString() => jsonEncode(toJson());
|
||||
|
||||
static SceneV2 fromJson(Map<String, dynamic> json) {
|
||||
return SceneV2(
|
||||
assets: (json['assets'] as Map<String, dynamic>).map(
|
||||
(key, value) => MapEntry(key, AssetInfo.fromJson(value)),
|
||||
),
|
||||
lights: (json['lights'] as List)
|
||||
.map((light) => LightInfo.fromJson(light))
|
||||
.toList(),
|
||||
cameras: json['cameras'].map((camera) => CameraInfo.fromJson),
|
||||
entities: (json['entities'] as List)
|
||||
.map((entity) => EntityInfo.fromJson(entity))
|
||||
.toList(),
|
||||
environment: json['environment'] != null
|
||||
? EnvironmentInfo.fromJson(json['environment'])
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
static SceneV2 fromJsonString(String jsonString) =>
|
||||
fromJson(jsonDecode(jsonString));
|
||||
}
|
||||
|
||||
class AssetInfo {
|
||||
final String uri;
|
||||
final AssetType type;
|
||||
|
||||
AssetInfo({required this.uri, required this.type});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'uri': uri,
|
||||
'type': type.toString().split('.').last,
|
||||
};
|
||||
|
||||
static AssetInfo fromJson(Map<String, dynamic> json) {
|
||||
return AssetInfo(
|
||||
uri: json['uri'],
|
||||
type: AssetType.values.firstWhere(
|
||||
(e) => e.toString().split('.').last == json['type'],
|
||||
orElse: () => AssetType.glb),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum AssetType { glb, gltf, geometryPrimitive }
|
||||
|
||||
class LightInfo {
|
||||
final LightType type;
|
||||
final Vector3 position;
|
||||
final Vector3 direction;
|
||||
final Color color;
|
||||
final double intensity;
|
||||
|
||||
LightInfo({
|
||||
required this.type,
|
||||
required this.position,
|
||||
required this.direction,
|
||||
required this.color,
|
||||
required this.intensity,
|
||||
});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'type': type.toString().split('.').last,
|
||||
'position': [position.x, position.y, position.z],
|
||||
'direction': [direction.x, direction.y, direction.z],
|
||||
'color': color.toJson(),
|
||||
'intensity': intensity,
|
||||
};
|
||||
|
||||
static LightInfo fromJson(Map<String, dynamic> json) {
|
||||
return LightInfo(
|
||||
type: LightType.values.firstWhere((e) => e.name == json['type']),
|
||||
position: Vector3.array(json['position'].cast<double>()),
|
||||
direction: Vector3.array(json['direction'].cast<double>()),
|
||||
color: Color.fromJson(json['color']),
|
||||
intensity: json['intensity'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class CameraInfo {
|
||||
final bool isActive;
|
||||
Matrix4 modelMatrix;
|
||||
Matrix4 projectionMatrix;
|
||||
|
||||
CameraInfo(
|
||||
{required this.isActive,
|
||||
required this.modelMatrix,
|
||||
required this.projectionMatrix});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'modelMatrix': modelMatrix.storage,
|
||||
'projectionMatrix': projectionMatrix.storage,
|
||||
'isActive': isActive,
|
||||
};
|
||||
|
||||
static CameraInfo fromJson(Map<String, dynamic> json) {
|
||||
return CameraInfo(
|
||||
modelMatrix:
|
||||
Matrix4.fromFloat64List(json['modelMatrix'].cast<double>()),
|
||||
projectionMatrix:
|
||||
Matrix4.fromFloat64List(json['modelMatrix'].cast<double>()),
|
||||
isActive: json["isActive"]);
|
||||
}
|
||||
}
|
||||
|
||||
class EntityInfo {
|
||||
final String assetUri;
|
||||
final Matrix4 transform;
|
||||
|
||||
EntityInfo({required this.assetUri, required this.transform});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'assetUri': assetUri,
|
||||
'transform': transform.storage,
|
||||
};
|
||||
|
||||
static EntityInfo fromJson(Map<String, dynamic> json) {
|
||||
return EntityInfo(
|
||||
assetUri: json['assetUri'],
|
||||
transform: Matrix4.fromList(List<double>.from(json['transform'])),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class EnvironmentInfo {
|
||||
final String? skyboxUri;
|
||||
final String? iblUri;
|
||||
|
||||
EnvironmentInfo({this.skyboxUri, this.iblUri});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'skyboxUri': skyboxUri,
|
||||
'iblUri': iblUri,
|
||||
};
|
||||
|
||||
static EnvironmentInfo fromJson(Map<String, dynamic> json) {
|
||||
return EnvironmentInfo(
|
||||
skyboxUri: json['skyboxUri'],
|
||||
iblUri: json['iblUri'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Color {
|
||||
final double r;
|
||||
final double g;
|
||||
final double b;
|
||||
final double a;
|
||||
|
||||
Color({required this.r, required this.g, required this.b, this.a = 1.0});
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'r': r,
|
||||
'g': g,
|
||||
'b': b,
|
||||
'a': a,
|
||||
};
|
||||
|
||||
static Color fromJson(Map<String, dynamic> json) {
|
||||
return Color(
|
||||
r: json['r'],
|
||||
g: json['g'],
|
||||
b: json['b'],
|
||||
a: json['a'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||
import 'thermion_viewer.dart';
|
||||
|
||||
///
|
||||
/// For now, this class just holds the entities that have been loaded (though not necessarily visible in the Filament Scene).
|
||||
///
|
||||
class SceneImpl extends Scene {
|
||||
ThermionViewer controller;
|
||||
|
||||
SceneImpl(this.controller);
|
||||
|
||||
@override
|
||||
ThermionEntity? selected;
|
||||
|
||||
final _onUpdatedController = StreamController<bool>.broadcast();
|
||||
@override
|
||||
Stream<bool> get onUpdated => _onUpdatedController.stream;
|
||||
|
||||
final _onLoadController = StreamController<ThermionEntity>.broadcast();
|
||||
@override
|
||||
Stream<ThermionEntity> get onLoad => _onLoadController.stream;
|
||||
|
||||
final _onUnloadController = StreamController<ThermionEntity>.broadcast();
|
||||
@override
|
||||
Stream<ThermionEntity> get onUnload => _onUnloadController.stream;
|
||||
|
||||
final _lights = <ThermionEntity>{};
|
||||
final _entities = <ThermionEntity>{};
|
||||
|
||||
void registerLight(ThermionEntity entity) {
|
||||
_lights.add(entity);
|
||||
_onLoadController.sink.add(entity);
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
void unregisterLight(ThermionEntity entity) async {
|
||||
var children = await controller.getChildEntities(entity, true);
|
||||
if (selected == entity || children.contains(selected)) {
|
||||
selected = null;
|
||||
controller.gizmo?.detach();
|
||||
}
|
||||
_lights.remove(entity);
|
||||
_onUnloadController.add(entity);
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
void unregisterEntity(ThermionEntity entity) async {
|
||||
var children = await controller.getChildEntities(entity, true);
|
||||
if (selected == entity || children.contains(selected)) {
|
||||
selected = null;
|
||||
|
||||
controller.gizmo?.detach();
|
||||
}
|
||||
_entities.remove(entity);
|
||||
_onUnloadController.add(entity);
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
void registerEntity(ThermionEntity entity) {
|
||||
_entities.add(entity);
|
||||
_onLoadController.sink.add(entity);
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
void clearLights() {
|
||||
for (final light in _lights) {
|
||||
if (selected == light) {
|
||||
selected = null;
|
||||
controller.gizmo?.detach();
|
||||
}
|
||||
_onUnloadController.add(light);
|
||||
}
|
||||
|
||||
_lights.clear();
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
void clearEntities() {
|
||||
for (final entity in _entities) {
|
||||
if (selected == entity) {
|
||||
selected = null;
|
||||
controller.gizmo?.detach();
|
||||
}
|
||||
_onUnloadController.add(entity);
|
||||
}
|
||||
_entities.clear();
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
///
|
||||
/// Lists all entities currently loaded (not necessarily active in the scene).
|
||||
///
|
||||
Iterable<ThermionEntity> listLights() {
|
||||
return _lights;
|
||||
}
|
||||
|
||||
@override
|
||||
Iterable<ThermionEntity> listEntities() {
|
||||
return _entities;
|
||||
}
|
||||
|
||||
void registerSelected(ThermionEntity entity) {
|
||||
selected = entity;
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
void unregisterSelected() {
|
||||
selected = null;
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
@override
|
||||
void select(ThermionEntity entity) {
|
||||
selected = entity;
|
||||
controller.gizmo?.attach(entity);
|
||||
_onUpdatedController.add(true);
|
||||
}
|
||||
|
||||
Future dispose() async {
|
||||
await _onLoadController.close();
|
||||
await _onUnloadController.close();
|
||||
await _onUpdatedController.close();
|
||||
}
|
||||
}
|
||||
@@ -1,745 +1,6 @@
|
||||
import 'dart:math';
|
||||
library thermion_viewer;
|
||||
|
||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
|
||||
typedef ThermionEntity = int;
|
||||
|
||||
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
|
||||
typedef FilamentPickResult = ({ThermionEntity entity, double x, double y});
|
||||
|
||||
enum LightType {
|
||||
SUN, //!< Directional light that also draws a sun's disk in the sky.
|
||||
DIRECTIONAL, //!< Directional light, emits light in a given direction.
|
||||
POINT, //!< Point light, emits light from a position, in all directions.
|
||||
FOCUSED_SPOT, //!< Physically correct spot light.
|
||||
SPOT,
|
||||
}
|
||||
|
||||
enum ShadowType {
|
||||
PCF, //!< percentage-closer filtered shadows (default)
|
||||
VSM, //!< variance shadows
|
||||
DPCF, //!< PCF with contact hardening simulation
|
||||
PCSS, //!< PCF with soft shadows and contact hardening
|
||||
}
|
||||
|
||||
// copied from filament/backened/DriverEnums.h
|
||||
enum PrimitiveType {
|
||||
// don't change the enums values (made to match GL)
|
||||
POINTS, //!< points
|
||||
LINES, //!< lines
|
||||
UNUSED1,
|
||||
LINE_STRIP, //!< line strip
|
||||
TRIANGLES, //!< triangles
|
||||
TRIANGLE_STRIP, //!< triangle strip
|
||||
}
|
||||
|
||||
enum ToneMapper { ACES, FILMIC, LINEAR }
|
||||
|
||||
// see filament Manipulator.h for more details
|
||||
enum ManipulatorMode { ORBIT, MAP, FREE_FLIGHT }
|
||||
|
||||
class TextureDetails {
|
||||
final int textureId;
|
||||
|
||||
// both width and height are in physical, not logical pixels
|
||||
final int width;
|
||||
final int height;
|
||||
|
||||
TextureDetails(
|
||||
{required this.textureId, required this.width, required this.height});
|
||||
}
|
||||
|
||||
abstract class ThermionViewer {
|
||||
|
||||
Future<bool> get initialized;
|
||||
|
||||
///
|
||||
/// The result(s) of calling [pick] (see below).
|
||||
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
||||
/// If [pick] is called without an active subscription to this stream, the results will be silently discarded.
|
||||
///
|
||||
Stream<FilamentPickResult> get pickResult;
|
||||
|
||||
///
|
||||
/// Whether the controller is currently rendering at [framerate].
|
||||
///
|
||||
bool get rendering;
|
||||
|
||||
///
|
||||
/// Set to true to continuously render the scene at the framerate specified by [setFrameRate] (60 fps by default).
|
||||
///
|
||||
Future setRendering(bool render);
|
||||
|
||||
///
|
||||
/// Render a single frame.
|
||||
///
|
||||
Future render();
|
||||
|
||||
///
|
||||
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
|
||||
///
|
||||
Future setFrameRate(int framerate);
|
||||
|
||||
///
|
||||
/// Destroys/disposes the viewer (including the entire scene). You cannot use the viewer after calling this method.
|
||||
///
|
||||
Future dispose();
|
||||
|
||||
///
|
||||
/// Set the background image to [path] (which should have a file extension .png, .jpg, or .ktx).
|
||||
/// This will be rendered at the maximum depth (i.e. behind all other objects including the skybox).
|
||||
/// If [fillHeight] is false, the image will be rendered at its original size. Note this may cause issues with pixel density so be sure to specify the correct resolution
|
||||
/// If [fillHeight] is true, the image will be stretched/compressed to fit the height of the viewport.
|
||||
///
|
||||
Future setBackgroundImage(String path, {bool fillHeight = false});
|
||||
|
||||
///
|
||||
/// Moves the background image to the relative offset from the origin (bottom-left) specified by [x] and [y].
|
||||
/// If [clamp] is true, the image cannot be positioned outside the bounds of the viewport.
|
||||
///
|
||||
Future setBackgroundImagePosition(double x, double y, {bool clamp = false});
|
||||
|
||||
///
|
||||
/// Removes the background image.
|
||||
///
|
||||
Future clearBackgroundImage();
|
||||
|
||||
///
|
||||
/// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox).
|
||||
///
|
||||
Future setBackgroundColor(double r, double g, double b, double alpha);
|
||||
|
||||
///
|
||||
/// Load a skybox from [skyboxPath] (which must be a .ktx file)
|
||||
///
|
||||
Future loadSkybox(String skyboxPath);
|
||||
|
||||
///
|
||||
/// Removes the skybox from the scene.
|
||||
///
|
||||
Future removeSkybox();
|
||||
|
||||
///
|
||||
/// Loads an image-based light from the specified path at the given intensity.
|
||||
/// Only one IBL can be active at any given time; if an IBL has already been loaded, it will be replaced.
|
||||
///
|
||||
Future loadIbl(String lightingPath, {double intensity = 30000});
|
||||
|
||||
///
|
||||
/// Rotates the IBL & skybox.
|
||||
///
|
||||
Future rotateIbl(Matrix3 rotation);
|
||||
|
||||
///
|
||||
/// Removes the image-based light from the scene.
|
||||
///
|
||||
Future removeIbl();
|
||||
|
||||
///
|
||||
/// Add a light to the scene.
|
||||
/// See LightManager.h for details
|
||||
/// Note that [sunAngularRadius] is in degrees,
|
||||
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
|
||||
///
|
||||
Future<ThermionEntity> addLight(
|
||||
LightType type,
|
||||
double colour,
|
||||
double intensity,
|
||||
double posX,
|
||||
double posY,
|
||||
double posZ,
|
||||
double dirX,
|
||||
double dirY,
|
||||
double dirZ,
|
||||
{double falloffRadius = 1.0,
|
||||
double spotLightConeInner = pi / 8,
|
||||
double spotLightConeOuter = pi / 4,
|
||||
double sunAngularRadius = 0.545,
|
||||
double sunHaloSize = 10.0,
|
||||
double sunHaloFallof = 80.0,
|
||||
bool castShadows = true});
|
||||
|
||||
Future removeLight(ThermionEntity light);
|
||||
|
||||
///
|
||||
/// Remove all lights (excluding IBL) from the scene.
|
||||
///
|
||||
Future clearLights();
|
||||
|
||||
///
|
||||
/// Load the .glb asset at the given path and insert into the scene.
|
||||
///
|
||||
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1});
|
||||
|
||||
///
|
||||
/// Create a new instance of [entity].
|
||||
///
|
||||
Future<ThermionEntity> createInstance(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns the number of instances of the asset associated with [entity].
|
||||
///
|
||||
Future<int> getInstanceCount(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns all instances of [entity].
|
||||
///
|
||||
Future<List<ThermionEntity>> getInstances(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Load the .gltf asset at the given path and insert into the scene.
|
||||
/// [relativeResourcePath] is the folder path where the glTF resources are stored;
|
||||
/// this is usually the parent directory of the .gltf file itself.
|
||||
///
|
||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||
{bool force = false});
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panStart(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panUpdate(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panEnd();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateStart(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateUpdate(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateEnd();
|
||||
|
||||
///
|
||||
/// Set the weights for all morph targets in [entity] to [weights].
|
||||
/// Note that [weights] must contain values for ALL morph targets, but no exception will be thrown if you don't do so (you'll just get incorrect results).
|
||||
/// If you only want to set one value, set all others to zero (check [getMorphTargetNames] if you need the get a list of all morph targets).
|
||||
/// IMPORTANT - this accepts the actual ThermionEntity with the relevant morph targets (unlike [getMorphTargetNames], which uses the parent entity and the child mesh name).
|
||||
/// Use [getChildEntityByName] if you are setting the weights for a child mesh.
|
||||
///
|
||||
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights);
|
||||
|
||||
///
|
||||
/// Gets the names of all morph targets for the child renderable [childEntity] under [entity].
|
||||
///
|
||||
Future<List<String>> getMorphTargetNames(
|
||||
ThermionEntity entity, ThermionEntity childEntity);
|
||||
|
||||
///
|
||||
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
|
||||
///
|
||||
Future<List<String>> getBoneNames(ThermionEntity entity, {int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Gets the names of all glTF animations embedded in the specified entity.
|
||||
///
|
||||
Future<List<String>> getAnimationNames(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns the length (in seconds) of the animation at the given index.
|
||||
///
|
||||
Future<double> getAnimationDuration(
|
||||
ThermionEntity entity, int animationIndex);
|
||||
|
||||
///
|
||||
/// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
|
||||
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
|
||||
/// throwing an exception if any cannot be found.
|
||||
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
|
||||
///
|
||||
Future setMorphAnimationData(
|
||||
ThermionEntity entity, MorphAnimationData animation,
|
||||
{List<String>? targetMeshNames});
|
||||
|
||||
///
|
||||
/// Resets all bones in the given entity to their rest pose.
|
||||
/// This should be done before every call to addBoneAnimation.
|
||||
///
|
||||
Future resetBones(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Enqueues and plays the [animation] for the specified bone(s).
|
||||
/// By default, frame data is interpreted as being in *parent* bone space;
|
||||
/// a 45 degree around Y means the bone will rotate 45 degrees around the
|
||||
/// Y axis of the parent bone *in its current orientation*.
|
||||
/// (i.e NOT the parent bone's rest position!).
|
||||
/// Currently, only [Space.ParentBone] and [Space.Model] are supported; if you want
|
||||
/// to transform to another space, you will need to do so manually.
|
||||
///
|
||||
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
|
||||
/// the current active glTF animation ("animation1") and the animation you
|
||||
/// set via this method ("animation2"). The bone orientations will be
|
||||
/// linearly interpolated between animation1 and animation2; at time 0,
|
||||
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
|
||||
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
|
||||
/// This will be applied in reverse after [fadeOutInSecs].
|
||||
///
|
||||
///
|
||||
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
||||
{int skinIndex = 0,
|
||||
double fadeInInSecs = 0.0,
|
||||
double fadeOutInSecs = 0.0,
|
||||
double maxDelta = 1.0});
|
||||
|
||||
///
|
||||
/// Gets the entity representing the bone at [boneIndex]/[skinIndex].
|
||||
/// The returned entity is only intended for use with [getWorldTransform].
|
||||
///
|
||||
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Gets the local (relative to parent) transform for [entity].
|
||||
///
|
||||
Future<Matrix4> getLocalTransform(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Gets the world transform for [entity].
|
||||
///
|
||||
Future<Matrix4> getWorldTransform(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Gets the inverse bind (pose) matrix for the bone.
|
||||
/// Note that [parent] must be the ThermionEntity returned by [loadGlb/loadGltf], not any other method ([getChildEntity] etc).
|
||||
/// This is because all joint information is internally stored with the parent entity.
|
||||
///
|
||||
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Sets the transform (relative to its parent) for [entity].
|
||||
///
|
||||
Future setTransform(ThermionEntity entity, Matrix4 transform);
|
||||
|
||||
///
|
||||
/// Updates the bone matrices for [entity] (which must be the ThermionEntity
|
||||
/// returned by [loadGlb/loadGltf]).
|
||||
/// Under the hood, this just calls [updateBoneMatrices] on the Animator
|
||||
/// instance of the relevant FilamentInstance (which uses the local
|
||||
/// bone transform and the inverse bind matrix to set the bone matrix).
|
||||
///
|
||||
Future updateBoneMatrices(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Directly set the bone matrix for the bone at the given index.
|
||||
/// Don't call this manually unless you know what you're doing.
|
||||
///
|
||||
Future setBoneTransform(
|
||||
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Removes/destroys the specified entity from the scene.
|
||||
/// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete.
|
||||
///
|
||||
Future removeEntity(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Removes/destroys all renderable entities from the scene (including cameras).
|
||||
/// All [ThermionEntity] handles will no longer be valid after this method is called; ensure you immediately discard all references to all entities once this method is complete.
|
||||
///
|
||||
Future clearEntities();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomBegin();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomUpdate(double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomEnd();
|
||||
|
||||
///
|
||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||
///
|
||||
Future playAnimation(ThermionEntity entity, int index,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0});
|
||||
|
||||
///
|
||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||
///
|
||||
Future playAnimationByName(ThermionEntity entity, String name,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0});
|
||||
|
||||
Future setAnimationFrame(
|
||||
ThermionEntity entity, int index, int animationFrame);
|
||||
|
||||
Future stopAnimation(ThermionEntity entity, int animationIndex);
|
||||
Future stopAnimationByName(ThermionEntity entity, String name);
|
||||
|
||||
///
|
||||
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
||||
///
|
||||
Future setCamera(ThermionEntity entity, String? name);
|
||||
|
||||
///
|
||||
/// Sets the current scene camera to the main camera (which is always available and added to every scene by default).
|
||||
///
|
||||
Future setMainCamera();
|
||||
|
||||
///
|
||||
/// Returns the entity associated with the main camera.
|
||||
///
|
||||
Future<ThermionEntity> getMainCamera();
|
||||
|
||||
///
|
||||
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
||||
///
|
||||
Future setCameraFov(double degrees, double width, double height);
|
||||
|
||||
///
|
||||
/// Sets the tone mapping (requires postprocessing).
|
||||
///
|
||||
Future setToneMapping(ToneMapper mapper);
|
||||
|
||||
///
|
||||
/// Sets the strength of the bloom.
|
||||
///
|
||||
Future setBloom(double bloom);
|
||||
|
||||
///
|
||||
/// Sets the focal length of the camera. Default value is 28.0.
|
||||
///
|
||||
Future setCameraFocalLength(double focalLength);
|
||||
|
||||
///
|
||||
/// Sets the distance (in world units) to the near/far planes for the active camera. Default values are 0.05/1000.0. See Camera.h for details.
|
||||
///
|
||||
Future setCameraCulling(double near, double far);
|
||||
|
||||
///
|
||||
/// Get the distance (in world units) to the near culling plane for the active camera.
|
||||
///
|
||||
Future<double> getCameraCullingNear();
|
||||
|
||||
///
|
||||
/// Get the distance (in world units) to the far culling plane for the active camera.
|
||||
///
|
||||
Future<double> getCameraCullingFar();
|
||||
|
||||
///
|
||||
/// Sets the focus distance for the camera.
|
||||
///
|
||||
Future setCameraFocusDistance(double focusDistance);
|
||||
|
||||
///
|
||||
/// Get the camera position in world space.
|
||||
///
|
||||
Future<Vector3> getCameraPosition();
|
||||
|
||||
///
|
||||
/// Get the camera's model matrix.
|
||||
///
|
||||
Future<Matrix4> getCameraModelMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's view matrix. See Camera.h for more details.
|
||||
///
|
||||
Future<Matrix4> getCameraViewMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's projection matrix. See Camera.h for more details.
|
||||
///
|
||||
Future<Matrix4> getCameraProjectionMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's culling projection matrix. See Camera.h for more details.
|
||||
///
|
||||
Future<Matrix4> getCameraCullingProjectionMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's culling frustum in world space. Returns a (vector_math) [Frustum] instance where plane0-plane6 define the left, right, bottom, top, far and near planes respectively.
|
||||
/// See Camera.h and (filament) Frustum.h for more details.
|
||||
///
|
||||
Future<Frustum> getCameraFrustum();
|
||||
|
||||
///
|
||||
/// Set the camera position in world space. Note this is not persistent - any viewport navigation will reset the camera transform.
|
||||
///
|
||||
Future setCameraPosition(double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Get the camera rotation matrix.
|
||||
///
|
||||
Future<Matrix3> getCameraRotation();
|
||||
|
||||
///
|
||||
/// Repositions the camera to the last vertex of the bounding box of [entity], looking at the penultimate vertex.
|
||||
///
|
||||
Future moveCameraToAsset(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Enables/disables frustum culling. Currently we don't expose a method for manipulating the camera projection/culling matrices so this is your only option to deal with unwanted near/far clipping.
|
||||
///
|
||||
Future setViewFrustumCulling(bool enabled);
|
||||
|
||||
///
|
||||
/// Sets the camera exposure.
|
||||
///
|
||||
Future setCameraExposure(
|
||||
double aperture, double shutterSpeed, double sensitivity);
|
||||
|
||||
///
|
||||
/// Rotate the camera by [rads] around the given axis. Note this is not persistent - any viewport navigation will reset the camera transform.
|
||||
///
|
||||
Future setCameraRotation(Quaternion quaternion);
|
||||
|
||||
///
|
||||
/// Sets the camera model matrix.
|
||||
///
|
||||
Future setCameraModelMatrix(List<double> matrix);
|
||||
|
||||
///
|
||||
/// Sets the `baseColorFactor` property for the material at index [materialIndex] in [entity] under node [meshName] to [color].
|
||||
///
|
||||
Future setMaterialColor(ThermionEntity entity, String meshName,
|
||||
int materialIndex, double r, double g, double b, double a);
|
||||
|
||||
///
|
||||
/// Scale [entity] to fit within the unit cube.
|
||||
///
|
||||
Future transformToUnitCube(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Directly sets the world space position for [entity] to the given coordinates, skipping all collision detection.
|
||||
///
|
||||
Future setPosition(ThermionEntity entity, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Directly sets the scale for [entity], skipping all collision detection.
|
||||
///
|
||||
Future setScale(ThermionEntity entity, double scale);
|
||||
|
||||
///
|
||||
/// Directly sets the rotation for [entity] to [rads] around the axis {x,y,z}, skipping all collision detection.
|
||||
///
|
||||
Future setRotation(
|
||||
ThermionEntity entity, double rads, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Queues an update to the worldspace position for [entity] to {x,y,z}.
|
||||
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
||||
///
|
||||
Future queuePositionUpdate(
|
||||
ThermionEntity entity, double x, double y, double z,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Queues an update to the worldspace rotation for [entity].
|
||||
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
||||
///
|
||||
Future queueRotationUpdate(
|
||||
ThermionEntity entity, double rads, double x, double y, double z,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Same as [queueRotationUpdate].
|
||||
///
|
||||
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Enable/disable postprocessing (disabled by default).
|
||||
///
|
||||
Future setPostProcessing(bool enabled);
|
||||
|
||||
///
|
||||
/// Enable/disable shadows (disabled by default).
|
||||
///
|
||||
Future setShadowsEnabled(bool enabled);
|
||||
|
||||
///
|
||||
/// Set shadow type.
|
||||
///
|
||||
Future setShadowType(ShadowType shadowType);
|
||||
|
||||
///
|
||||
/// Set soft shadow options (ShadowType DPCF and PCSS)
|
||||
///
|
||||
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale);
|
||||
|
||||
///
|
||||
/// Set antialiasing options.
|
||||
///
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
||||
|
||||
///
|
||||
/// Sets the rotation for [entity] to the specified quaternion.
|
||||
///
|
||||
Future setRotationQuat(ThermionEntity entity, Quaternion rotation);
|
||||
|
||||
///
|
||||
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
|
||||
///
|
||||
Future reveal(ThermionEntity entity, String? meshName);
|
||||
|
||||
///
|
||||
/// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity].
|
||||
/// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering.
|
||||
///
|
||||
Future hide(ThermionEntity entity, String? meshName);
|
||||
|
||||
///
|
||||
/// Used to select the entity in the scene at the given viewport coordinates.
|
||||
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
|
||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||
///
|
||||
void pick(int x, int y);
|
||||
|
||||
///
|
||||
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
|
||||
///
|
||||
String? getNameForEntity(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Sets the options for manipulating the camera via the viewport.
|
||||
/// ManipulatorMode.FREE_FLIGHT and ManipulatorMode.MAP are currently unsupported and will throw an exception.
|
||||
///
|
||||
Future setCameraManipulatorOptions(
|
||||
{ManipulatorMode mode = ManipulatorMode.ORBIT,
|
||||
double orbitSpeedX = 0.01,
|
||||
double orbitSpeedY = 0.01,
|
||||
double zoomSpeed = 0.01});
|
||||
|
||||
///
|
||||
/// Returns all child entities under [parent].
|
||||
///
|
||||
Future<List<ThermionEntity>> getChildEntities(
|
||||
ThermionEntity parent, bool renderableOnly);
|
||||
|
||||
///
|
||||
/// Finds the child entity named [childName] associated with the given parent.
|
||||
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
|
||||
///
|
||||
Future<ThermionEntity> getChildEntity(
|
||||
ThermionEntity parent, String childName);
|
||||
|
||||
///
|
||||
/// List the name of all child entities under the given entity.
|
||||
///
|
||||
Future<List<String>> getChildEntityNames(ThermionEntity entity,
|
||||
{bool renderableOnly = true});
|
||||
|
||||
///
|
||||
/// If [recording] is set to true, each frame the framebuffer/texture will be written to /tmp/output_*.png.
|
||||
/// This will impact performance; handle with care.
|
||||
///
|
||||
Future setRecording(bool recording);
|
||||
|
||||
///
|
||||
/// Sets the output directory where recorded PNGs will be placed.
|
||||
///
|
||||
Future setRecordingOutputDirectory(String outputDirectory);
|
||||
|
||||
///
|
||||
/// An [entity] will only be animatable after an animation component is attached.
|
||||
/// Any calls to [playAnimation]/[setBoneAnimation]/[setMorphAnimation] will have no visual effect until [addAnimationComponent] has been called on the instance.
|
||||
///
|
||||
Future addAnimationComponent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Removes an animation component from [entity].
|
||||
///
|
||||
Future removeAnimationComponent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Makes [entity] collidable.
|
||||
/// This allows you to call [testCollisions] with any other entity ("entity B") to see if [entity] has collided with entity B. The callback will be invoked if so.
|
||||
/// Alternatively, if [affectsTransform] is true and this entity collides with another entity, any queued position updates to the latter entity will be ignored.
|
||||
///
|
||||
Future addCollisionComponent(ThermionEntity entity,
|
||||
{void Function(int entityId1, int entityId2)? callback,
|
||||
bool affectsTransform = false});
|
||||
|
||||
///
|
||||
/// Removes the collision component from [entity], meaning this will no longer be tested when [testCollisions] or [queuePositionUpdate] is called with another entity.
|
||||
///
|
||||
Future removeCollisionComponent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Creates a (renderable) entity with the specified geometry and adds to the scene.
|
||||
///
|
||||
Future createGeometry(List<double> vertices, List<int> indices,
|
||||
{String? materialPath,
|
||||
PrimitiveType primitiveType = PrimitiveType.TRIANGLES});
|
||||
|
||||
///
|
||||
/// Gets the parent transform of [child].
|
||||
///
|
||||
Future<ThermionEntity?> getParent(ThermionEntity child);
|
||||
|
||||
///
|
||||
/// Sets the parent transform of [child] to [parent].
|
||||
///
|
||||
Future setParent(ThermionEntity child, ThermionEntity parent);
|
||||
|
||||
///
|
||||
/// Test all collidable entities against this entity to see if any have collided.
|
||||
/// This method returns void; the relevant callback passed to [addCollisionComponent] will be fired if a collision is detected.
|
||||
///
|
||||
Future testCollisions(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
|
||||
///
|
||||
Future setPriority(ThermionEntity entityId, int priority);
|
||||
|
||||
///
|
||||
/// The Scene holds all loaded entities/lights.
|
||||
///
|
||||
Scene get scene;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
AbstractGizmo? get gizmo;
|
||||
|
||||
///
|
||||
/// Register a callback to be invoked when this viewer is disposed.
|
||||
///
|
||||
void onDispose(Future Function() callback);
|
||||
|
||||
}
|
||||
|
||||
abstract class AbstractGizmo {
|
||||
bool get isActive;
|
||||
|
||||
void translate(double transX, double transY);
|
||||
|
||||
void reset();
|
||||
|
||||
void attach(ThermionEntity entity);
|
||||
|
||||
void detach();
|
||||
}
|
||||
export 'viewer/thermion_viewer_base.dart';
|
||||
export 'viewer/thermion_viewer_stub.dart'
|
||||
if (dart.library.io) 'viewer/ffi/thermion_viewer_ffi.dart'
|
||||
if (dart.library.js_interop) 'viewer/web/thermion_viewer_wasm.dart';
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import '../compatibility/compatibility.dart';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/ffi/src/thermion_dart.g.dart';
|
||||
|
||||
class DartResourceLoader {
|
||||
static final _assets = <int, Pointer>{};
|
||||
|
||||
334
thermion_dart/lib/thermion_dart/utils/geometry.dart
Normal file
334
thermion_dart/lib/thermion_dart/utils/geometry.dart
Normal file
@@ -0,0 +1,334 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/geometry.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
|
||||
|
||||
class GeometryHelper {
|
||||
static Geometry sphere({bool normals = true, bool uvs = true}) {
|
||||
int latitudeBands = 20;
|
||||
int longitudeBands = 20;
|
||||
|
||||
List<double> verticesList = [];
|
||||
List<double> normalsList = [];
|
||||
List<double> uvsList = [];
|
||||
List<int> indices = [];
|
||||
|
||||
for (int latNumber = 0; latNumber <= latitudeBands; latNumber++) {
|
||||
double theta = latNumber * pi / latitudeBands;
|
||||
double sinTheta = sin(theta);
|
||||
double cosTheta = cos(theta);
|
||||
|
||||
for (int longNumber = 0; longNumber <= longitudeBands; longNumber++) {
|
||||
double phi = longNumber * 2 * pi / longitudeBands;
|
||||
double sinPhi = sin(phi);
|
||||
double cosPhi = cos(phi);
|
||||
|
||||
double x = cosPhi * sinTheta;
|
||||
double y = cosTheta;
|
||||
double z = sinPhi * sinTheta;
|
||||
|
||||
verticesList.addAll([x, y, z]);
|
||||
normalsList.addAll([x, y, z]);
|
||||
|
||||
uvsList.addAll([longNumber / longitudeBands, latNumber / latitudeBands]);
|
||||
}
|
||||
}
|
||||
|
||||
for (int latNumber = 0; latNumber < latitudeBands; latNumber++) {
|
||||
for (int longNumber = 0; longNumber < longitudeBands; longNumber++) {
|
||||
int first = (latNumber * (longitudeBands + 1)) + longNumber;
|
||||
int second = first + longitudeBands + 1;
|
||||
|
||||
indices.addAll([first, second, first + 1, second, second + 1, first + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
Float32List vertices = Float32List.fromList(verticesList);
|
||||
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
|
||||
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
|
||||
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
|
||||
static Geometry cube({bool normals = true, bool uvs = true}) {
|
||||
final vertices = Float32List.fromList([
|
||||
// Front face
|
||||
-1, -1, 1,
|
||||
1, -1, 1,
|
||||
1, 1, 1,
|
||||
-1, 1, 1,
|
||||
|
||||
// Back face
|
||||
-1, -1, -1,
|
||||
-1, 1, -1,
|
||||
1, 1, -1,
|
||||
1, -1, -1,
|
||||
|
||||
// Top face
|
||||
-1, 1, -1,
|
||||
-1, 1, 1,
|
||||
1, 1, 1,
|
||||
1, 1, -1,
|
||||
|
||||
// Bottom face
|
||||
-1, -1, -1,
|
||||
1, -1, -1,
|
||||
1, -1, 1,
|
||||
-1, -1, 1,
|
||||
|
||||
// Right face
|
||||
1, -1, -1,
|
||||
1, 1, -1,
|
||||
1, 1, 1,
|
||||
1, -1, 1,
|
||||
|
||||
// Left face
|
||||
-1, -1, -1,
|
||||
-1, -1, 1,
|
||||
-1, 1, 1,
|
||||
-1, 1, -1,
|
||||
]);
|
||||
|
||||
final _normals = normals ? Float32List.fromList([
|
||||
// Front face
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
0, 0, 1,
|
||||
|
||||
// Back face
|
||||
0, 0, -1,
|
||||
0, 0, -1,
|
||||
0, 0, -1,
|
||||
0, 0, -1,
|
||||
|
||||
// Top face
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
|
||||
// Bottom face
|
||||
0, -1, 0,
|
||||
0, -1, 0,
|
||||
0, -1, 0,
|
||||
0, -1, 0,
|
||||
|
||||
// Right face
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
1, 0, 0,
|
||||
|
||||
// Left face
|
||||
-1, 0, 0,
|
||||
-1, 0, 0,
|
||||
-1, 0, 0,
|
||||
-1, 0, 0,
|
||||
]) : null;
|
||||
|
||||
final _uvs = uvs ? Float32List.fromList([
|
||||
// Front face
|
||||
1/3, 1/3,
|
||||
2/3, 1/3,
|
||||
2/3, 2/3,
|
||||
1/3, 2/3,
|
||||
|
||||
// Back face
|
||||
2/3, 2/3,
|
||||
2/3, 1,
|
||||
1, 1,
|
||||
1, 2/3,
|
||||
|
||||
// Top face
|
||||
1/3, 0,
|
||||
1/3, 1/3,
|
||||
2/3, 1/3,
|
||||
2/3, 0,
|
||||
|
||||
// Bottom face
|
||||
1/3, 2/3,
|
||||
2/3, 2/3,
|
||||
2/3, 1,
|
||||
1/3, 1,
|
||||
|
||||
// Right face
|
||||
2/3, 1/3,
|
||||
2/3, 2/3,
|
||||
1, 2/3,
|
||||
1, 1/3,
|
||||
|
||||
// Left face
|
||||
0, 1/3,
|
||||
1/3, 1/3,
|
||||
1/3, 2/3,
|
||||
0, 2/3,
|
||||
]) : null;
|
||||
|
||||
final indices = [
|
||||
// Front face
|
||||
0, 1, 2, 0, 2, 3,
|
||||
// Back face
|
||||
4, 5, 6, 4, 6, 7,
|
||||
// Top face
|
||||
8, 9, 10, 8, 10, 11,
|
||||
// Bottom face
|
||||
12, 13, 14, 12, 14, 15,
|
||||
// Right face
|
||||
16, 17, 18, 16, 18, 19,
|
||||
// Left face
|
||||
20, 21, 22, 20, 22, 23
|
||||
];
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
|
||||
static Geometry cylinder({double radius = 1.0, double length = 1.0, bool normals = true, bool uvs = true }) {
|
||||
int segments = 32;
|
||||
List<double> verticesList = [];
|
||||
List<double> normalsList = [];
|
||||
List<double> uvsList = [];
|
||||
List<int> indices = [];
|
||||
|
||||
// Create vertices, normals, and UVs
|
||||
for (int i = 0; i <= segments; i++) {
|
||||
double theta = i * 2 * pi / segments;
|
||||
double x = radius * cos(theta);
|
||||
double z = radius * sin(theta);
|
||||
|
||||
// Top circle
|
||||
verticesList.addAll([x, length / 2, z]);
|
||||
normalsList.addAll([x / radius, 0, z / radius]);
|
||||
uvsList.addAll([i / segments, 1]);
|
||||
|
||||
// Bottom circle
|
||||
verticesList.addAll([x, -length / 2, z]);
|
||||
normalsList.addAll([x / radius, 0, z / radius]);
|
||||
uvsList.addAll([i / segments, 0]);
|
||||
}
|
||||
|
||||
// Create indices
|
||||
for (int i = 0; i < segments; i++) {
|
||||
int topFirst = i * 2;
|
||||
int topSecond = (i + 1) * 2;
|
||||
int bottomFirst = topFirst + 1;
|
||||
int bottomSecond = topSecond + 1;
|
||||
|
||||
// Top face (counter-clockwise)
|
||||
indices.addAll([segments * 2, topSecond, topFirst]);
|
||||
// Bottom face (counter-clockwise when viewed from below)
|
||||
indices.addAll([segments * 2 + 1, bottomFirst, bottomSecond]);
|
||||
// Side faces (counter-clockwise)
|
||||
indices.addAll([topFirst, bottomFirst, topSecond]);
|
||||
indices.addAll([bottomFirst, bottomSecond, topSecond]);
|
||||
}
|
||||
|
||||
// Add center vertices, normals, and UVs for top and bottom faces
|
||||
verticesList.addAll([0, length / 2, 0]); // Top center
|
||||
normalsList.addAll([0, 1, 0]);
|
||||
uvsList.addAll([0.5, 0.5]); // Center of top face
|
||||
|
||||
verticesList.addAll([0, -length / 2, 0]); // Bottom center
|
||||
normalsList.addAll([0, -1, 0]);
|
||||
uvsList.addAll([0.5, 0.5]); // Center of bottom face
|
||||
|
||||
// Add top and bottom face normals and UVs
|
||||
for (int i = 0; i <= segments; i++) {
|
||||
normalsList.addAll([0, 1, 0]); // Top face normal
|
||||
normalsList.addAll([0, -1, 0]); // Bottom face normal
|
||||
|
||||
double u = 0.5 + 0.5 * cos(i * 2 * pi / segments);
|
||||
double v = 0.5 + 0.5 * sin(i * 2 * pi / segments);
|
||||
uvsList.addAll([u, v]); // Top face UV
|
||||
uvsList.addAll([u, v]); // Bottom face UV
|
||||
}
|
||||
|
||||
Float32List vertices = Float32List.fromList(verticesList);
|
||||
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
|
||||
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
|
||||
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
|
||||
static Geometry conic({double radius = 1.0, double length = 1.0, bool normals = true, bool uvs = true}) {
|
||||
int segments = 32;
|
||||
List<double> verticesList = [];
|
||||
List<double> normalsList = [];
|
||||
List<double> uvsList = [];
|
||||
List<int> indices = [];
|
||||
|
||||
// Create vertices, normals, and UVs
|
||||
for (int i = 0; i <= segments; i++) {
|
||||
double theta = i * 2 * pi / segments;
|
||||
double x = radius * cos(theta);
|
||||
double z = radius * sin(theta);
|
||||
|
||||
// Base circle
|
||||
verticesList.addAll([x, 0, z]);
|
||||
|
||||
// Calculate normal for the side
|
||||
double nx = x / sqrt(x * x + length * length);
|
||||
double nz = z / sqrt(z * z + length * length);
|
||||
double ny = radius / sqrt(radius * radius + length * length);
|
||||
normalsList.addAll([nx, ny, nz]);
|
||||
|
||||
// UV coordinates
|
||||
uvsList.addAll([i / segments, 0]);
|
||||
}
|
||||
// Apex
|
||||
verticesList.addAll([0, length, 0]);
|
||||
normalsList.addAll([0, 1, 0]); // Normal at apex points straight up
|
||||
uvsList.addAll([0.5, 1]); // UV for apex
|
||||
|
||||
// Create indices
|
||||
for (int i = 0; i < segments; i++) {
|
||||
// Base face (fixed to counterclockwise)
|
||||
indices.addAll([segments + 1, i + 1, i]);
|
||||
// Side faces (already correct)
|
||||
indices.addAll([i, segments, i + 1]);
|
||||
}
|
||||
|
||||
// Add base face normals and UVs
|
||||
for (int i = 0; i <= segments; i++) {
|
||||
normalsList.addAll([0, -1, 0]); // Base face normal
|
||||
double u = 0.5 + 0.5 * cos(i * 2 * pi / segments);
|
||||
double v = 0.5 + 0.5 * sin(i * 2 * pi / segments);
|
||||
uvsList.addAll([u, v]); // Base face UV
|
||||
}
|
||||
|
||||
Float32List vertices = Float32List.fromList(verticesList);
|
||||
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
|
||||
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
|
||||
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
|
||||
static Geometry plane({double width = 1.0, double height = 1.0, bool normals = true, bool uvs = true}) {
|
||||
Float32List vertices = Float32List.fromList([
|
||||
-width / 2, 0, -height / 2,
|
||||
width / 2, 0, -height / 2,
|
||||
width / 2, 0, height / 2,
|
||||
-width / 2, 0, height / 2,
|
||||
]);
|
||||
|
||||
Float32List? _normals = normals ? Float32List.fromList([
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
0, 1, 0,
|
||||
]) : null;
|
||||
|
||||
Float32List? _uvs = uvs ? Float32List.fromList([
|
||||
0, 0,
|
||||
1, 0,
|
||||
1, 1,
|
||||
0, 1,
|
||||
]) : null;
|
||||
|
||||
List<int> indices = [
|
||||
0, 2, 1,
|
||||
0, 3, 2,
|
||||
];
|
||||
|
||||
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
import 'package:vector_math/vector_math_64.dart' as v;
|
||||
|
||||
class LightOptions {
|
||||
String? iblPath;
|
||||
double iblIntensity;
|
||||
int directionalType;
|
||||
double directionalColor;
|
||||
double directionalIntensity;
|
||||
bool directionalCastShadows;
|
||||
late v.Vector3 directionalPosition;
|
||||
late v.Vector3 directionalDirection;
|
||||
|
||||
LightOptions(
|
||||
{required this.iblPath,
|
||||
required this.iblIntensity,
|
||||
required this.directionalType,
|
||||
required this.directionalColor,
|
||||
required this.directionalIntensity,
|
||||
required this.directionalCastShadows,
|
||||
v.Vector3? directionalDirection,
|
||||
v.Vector3? directionalPosition}) {
|
||||
this.directionalDirection = directionalDirection == null
|
||||
? v.Vector3(0, -1, 0)
|
||||
: directionalDirection;
|
||||
this.directionalPosition = directionalPosition == null
|
||||
? v.Vector3(0, 100, 0)
|
||||
: directionalPosition;
|
||||
}
|
||||
}
|
||||
38
thermion_dart/lib/thermion_dart/utils/matrix.dart
Normal file
38
thermion_dart/lib/thermion_dart/utils/matrix.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
// Helper function to convert double4x4 to Matrix4
|
||||
import 'package:thermion_dart/thermion_dart/viewer/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:ffi';
|
||||
|
||||
Matrix4 double4x4ToMatrix4(double4x4 mat) {
|
||||
return Matrix4.fromList([
|
||||
mat.col1[0],
|
||||
mat.col1[1],
|
||||
mat.col1[2],
|
||||
mat.col1[3],
|
||||
mat.col2[0],
|
||||
mat.col2[1],
|
||||
mat.col2[2],
|
||||
mat.col2[3],
|
||||
mat.col3[0],
|
||||
mat.col3[1],
|
||||
mat.col3[2],
|
||||
mat.col3[3],
|
||||
mat.col4[0],
|
||||
mat.col4[1],
|
||||
mat.col4[2],
|
||||
mat.col4[3],
|
||||
]);
|
||||
}
|
||||
|
||||
double4x4 matrix4ToDouble4x4(Matrix4 mat) {
|
||||
final out = Struct.create<double4x4>();
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
out.col1[i] = mat.storage[i];
|
||||
out.col2[i] = mat.storage[i + 4];
|
||||
out.col3[i] = mat.storage[i + 8];
|
||||
out.col4[i] = mat.storage[i + 12];
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
final allocator = calloc;
|
||||
|
||||
void using(Pointer ptr, Future Function(Pointer ptr) function) async {
|
||||
await function.call(ptr);
|
||||
allocator.free(ptr);
|
||||
}
|
||||
86
thermion_dart/lib/thermion_dart/viewer/events.dart
Normal file
86
thermion_dart/lib/thermion_dart/viewer/events.dart
Normal file
@@ -0,0 +1,86 @@
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/entities.dart';
|
||||
import 'shared_types/shared_types.dart';
|
||||
|
||||
///
|
||||
/// To ensure we can easily store/recreate a particular, [ThermionViewer] will raise an event whenever an
|
||||
/// entity is added/removed.
|
||||
///
|
||||
enum EventType { EntityAdded, EntityRemoved, EntityHidden, EntityRevealed, ClearLights }
|
||||
|
||||
///
|
||||
/// An "entity added" event must provide sufficient detail to enable that asset to be reloaded in future.
|
||||
/// This requires a bit more legwork because entities may be lights (direct/indirect), geometry or gltf.
|
||||
///
|
||||
enum EntityType { Geometry, Gltf, DirectLight, IBL }
|
||||
|
||||
class SceneUpdateEvent {
|
||||
late final ThermionEntity? entity;
|
||||
late final EventType eventType;
|
||||
|
||||
EntityType get addedEntityType {
|
||||
if (_directLight != null) {
|
||||
return EntityType.DirectLight;
|
||||
} else if (_ibl != null) {
|
||||
return EntityType.IBL;
|
||||
} else if (_gltf != null) {
|
||||
return EntityType.Gltf;
|
||||
} else if (_geometry != null) {
|
||||
return EntityType.Geometry;
|
||||
} else {
|
||||
throw Exception("Unknown entity type");
|
||||
}
|
||||
}
|
||||
|
||||
DirectLight? _directLight;
|
||||
IBL? _ibl;
|
||||
GLTF? _gltf;
|
||||
Geometry? _geometry;
|
||||
|
||||
SceneUpdateEvent.remove(this.entity) {
|
||||
this.eventType = EventType.EntityRemoved;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.reveal(this.entity) {
|
||||
this.eventType = EventType.EntityRevealed;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.hide(this.entity) {
|
||||
this.eventType = EventType.EntityHidden;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.addDirectLight(this.entity, this._directLight) {
|
||||
this.eventType = EventType.EntityAdded;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.addIbl(this.entity, this._ibl) {
|
||||
this.eventType = EventType.EntityAdded;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.addGltf(this.entity, this._gltf) {
|
||||
this.eventType = EventType.EntityAdded;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.addGeometry(this.entity, this._geometry) {
|
||||
this.eventType = EventType.EntityAdded;
|
||||
}
|
||||
|
||||
SceneUpdateEvent.clearLights() {
|
||||
this.eventType = EventType.ClearLights;
|
||||
}
|
||||
|
||||
DirectLight getDirectLight() {
|
||||
return _directLight!;
|
||||
}
|
||||
|
||||
IBL getAsIBL() {
|
||||
return _ibl!;
|
||||
}
|
||||
|
||||
GLTF getAsGLTF() {
|
||||
return _gltf!;
|
||||
}
|
||||
|
||||
Geometry getAsGeometry() {
|
||||
return _geometry!;
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,11 @@ export 'thermion_dart.g.dart';
|
||||
|
||||
final allocator = calloc;
|
||||
|
||||
void using(Pointer ptr, Future Function(Pointer ptr) function) async {
|
||||
await function.call(ptr);
|
||||
allocator.free(ptr);
|
||||
}
|
||||
|
||||
Future<void> withVoidCallback(
|
||||
Function(Pointer<NativeFunction<Void Function()>>) func) async {
|
||||
final completer = Completer();
|
||||
@@ -21,16 +26,16 @@ Future<void> withVoidCallback(
|
||||
nativeCallable.close();
|
||||
}
|
||||
|
||||
Future<int> withVoidPointerCallback(
|
||||
Function(Pointer<NativeFunction<Void Function(Pointer<Void>)>>)
|
||||
Future<int> withPointerCallback<T extends NativeType>(
|
||||
Function(Pointer<NativeFunction<Void Function(Pointer<T>)>>)
|
||||
func) async {
|
||||
final completer = Completer<Pointer<Void>>();
|
||||
final completer = Completer<Pointer<T>>();
|
||||
// ignore: prefer_function_declarations_over_variables
|
||||
void Function(Pointer<Void>) callback = (Pointer<Void> ptr) {
|
||||
completer.complete(ptr);
|
||||
void Function(Pointer<NativeType>) callback = (Pointer<NativeType> ptr) {
|
||||
completer.complete(ptr.cast<T>());
|
||||
};
|
||||
final nativeCallable =
|
||||
NativeCallable<Void Function(Pointer<Void>)>.listener(callback);
|
||||
NativeCallable<Void Function(Pointer<NativeType>)>.listener(callback);
|
||||
func.call(nativeCallable.nativeFunction);
|
||||
var ptr = await completer.future;
|
||||
nativeCallable.close();
|
||||
@@ -82,4 +87,3 @@ Future<String> withCharPtrCallback(
|
||||
return completer.future;
|
||||
}
|
||||
|
||||
class Compatibility {}
|
||||
@@ -0,0 +1,22 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart/utils/matrix.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class ThermionFFICamera extends Camera {
|
||||
final Pointer<TCamera> pointer;
|
||||
|
||||
ThermionFFICamera(this.pointer);
|
||||
|
||||
@override
|
||||
Future setProjectionMatrixWithCulling(Matrix4 projectionMatrix,
|
||||
double near, double far) async {
|
||||
Camera_setCustomProjectionWithCulling(
|
||||
pointer,
|
||||
matrix4ToDouble4x4(projectionMatrix),
|
||||
near,
|
||||
far);
|
||||
}
|
||||
}
|
||||
2127
thermion_dart/lib/thermion_dart/viewer/ffi/src/thermion_dart.g.dart
Normal file
2127
thermion_dart/lib/thermion_dart/viewer/ffi/src/thermion_dart.g.dart
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,4 @@
|
||||
library;
|
||||
|
||||
export 'src/thermion_viewer_ffi.dart' show ThermionViewerFFI;
|
||||
export 'src/camera_ffi.dart';
|
||||
@@ -0,0 +1,8 @@
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
abstract class Camera {
|
||||
|
||||
Future setProjectionMatrixWithCulling(Matrix4 projectionMatrix, double near, double far);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
library;
|
||||
|
||||
export 'geometry.dart';
|
||||
export 'gltf.dart';
|
||||
|
||||
export 'light_options.dart';
|
||||
|
||||
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
|
||||
typedef ThermionEntity = int;
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
|
||||
|
||||
class Geometry {
|
||||
final Float32List vertices;
|
||||
final Uint16List indices;
|
||||
final Float32List normals;
|
||||
final Float32List uvs;
|
||||
final PrimitiveType primitiveType;
|
||||
|
||||
Geometry(
|
||||
this.vertices,
|
||||
List<int> indices, {
|
||||
Float32List? normals,
|
||||
Float32List? uvs,
|
||||
this.primitiveType = PrimitiveType.TRIANGLES,
|
||||
}) : indices = Uint16List.fromList(indices),
|
||||
normals = normals ?? Float32List(0),
|
||||
uvs = uvs ?? Float32List(0) {
|
||||
assert(this.uvs.length == 0 || this.uvs.length == (vertices.length ~/ 3) * 2);
|
||||
}
|
||||
|
||||
void scale(double factor) {
|
||||
for (int i = 0; i < vertices.length; i++) {
|
||||
vertices[i] = vertices[i] * factor;
|
||||
}
|
||||
}
|
||||
|
||||
bool get hasNormals => normals.isNotEmpty;
|
||||
bool get hasUVs => uvs.isNotEmpty;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
class GLTF {
|
||||
final String uri;
|
||||
final int numInstances;
|
||||
|
||||
GLTF(this.uri, this.numInstances);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
enum LightType {
|
||||
SUN, //!< Directional light that also draws a sun's disk in the sky.
|
||||
DIRECTIONAL, //!< Directional light, emits light in a given direction.
|
||||
POINT, //!< Point light, emits light from a position, in all directions.
|
||||
FOCUSED_SPOT, //!< Physically correct spot light.
|
||||
SPOT,
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
import 'dart:math';
|
||||
import 'package:vector_math/vector_math_64.dart' as v;
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'light.dart';
|
||||
|
||||
class IBL {
|
||||
String? iblPath;
|
||||
final double iblIntensity;
|
||||
|
||||
IBL(this.iblIntensity);
|
||||
}
|
||||
|
||||
class DirectLight {
|
||||
final LightType type;
|
||||
final double color;
|
||||
final double intensity;
|
||||
final bool castShadows;
|
||||
late final v.Vector3 position;
|
||||
late final v.Vector3 direction;
|
||||
final double falloffRadius;
|
||||
final double spotLightConeInner;
|
||||
final double spotLightConeOuter;
|
||||
final double sunAngularRadius;
|
||||
final double sunHaloSize;
|
||||
final double sunHaloFallof;
|
||||
|
||||
DirectLight({
|
||||
required this.type,
|
||||
required this.color,
|
||||
required this.intensity,
|
||||
this.castShadows = false,
|
||||
required this.direction,
|
||||
required this.position,
|
||||
this.falloffRadius = 1.0,
|
||||
this.spotLightConeInner = pi / 8,
|
||||
this.spotLightConeOuter = pi / 4,
|
||||
this.sunAngularRadius = 0.545,
|
||||
this.sunHaloSize = 10.0,
|
||||
this.sunHaloFallof = 80.0,
|
||||
});
|
||||
|
||||
DirectLight.point({
|
||||
double color = 6500,
|
||||
double intensity = 100000,
|
||||
bool castShadows = false,
|
||||
Vector3? position,
|
||||
double falloffRadius = 1.0,
|
||||
}) : this(
|
||||
type: LightType.POINT,
|
||||
color: color,
|
||||
intensity: intensity,
|
||||
castShadows: castShadows,
|
||||
position: position ?? Vector3(0, 1, 0),
|
||||
direction: Vector3.zero(),
|
||||
falloffRadius: falloffRadius,
|
||||
);
|
||||
|
||||
DirectLight.sun({
|
||||
double color = 6500,
|
||||
double intensity = 100000,
|
||||
bool castShadows = true,
|
||||
Vector3? direction,
|
||||
double sunAngularRadius = 0.545,
|
||||
double sunHaloSize = 10.0,
|
||||
double sunHaloFalloff = 80.0,
|
||||
}) : this(
|
||||
type: LightType.DIRECTIONAL,
|
||||
color: color,
|
||||
intensity: intensity,
|
||||
castShadows: castShadows,
|
||||
position: Vector3(0, 0, 0),
|
||||
direction: direction ?? Vector3(0, -1, 0),
|
||||
sunAngularRadius: sunAngularRadius,
|
||||
sunHaloSize: sunHaloSize,
|
||||
sunHaloFallof: sunHaloFalloff,
|
||||
);
|
||||
|
||||
DirectLight.spot({
|
||||
double color = 6500,
|
||||
double intensity = 100000,
|
||||
bool castShadows = true,
|
||||
Vector3? position,
|
||||
Vector3? direction,
|
||||
double falloffRadius = 1.0,
|
||||
double spotLightConeInner = pi / 8,
|
||||
double spotLightConeOuter = pi / 4,
|
||||
}) : this(
|
||||
type: LightType.SPOT,
|
||||
color: color,
|
||||
intensity: intensity,
|
||||
castShadows: castShadows,
|
||||
position: position ?? Vector3(0, 1, 0),
|
||||
direction: direction ?? Vector3(0, -1, 0),
|
||||
falloffRadius: falloffRadius,
|
||||
spotLightConeInner: spotLightConeInner,
|
||||
spotLightConeOuter: spotLightConeOuter,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
// see filament Manipulator.h for more details
|
||||
@Deprecated(
|
||||
"This is used the native pointer manipulator Prefer ThermionGestureHandler instead")
|
||||
enum ManipulatorMode { ORBIT, MAP, FREE_FLIGHT }
|
||||
@@ -0,0 +1,6 @@
|
||||
abstract class MaterialInstance {
|
||||
Future setDepthWriteEnabled(bool enabled);
|
||||
Future setDepthCullingEnabled(bool enabled);
|
||||
}
|
||||
|
||||
enum AlphaMode { OPAQUE, MASK, BLEND }
|
||||
@@ -0,0 +1,5 @@
|
||||
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/shared_types.dart';
|
||||
|
||||
typedef FilamentPickResult = ({ThermionEntity entity, double x, double y});
|
||||
typedef ThermionPickResult = FilamentPickResult;
|
||||
@@ -0,0 +1,10 @@
|
||||
// copied from filament/backened/DriverEnums.h
|
||||
enum PrimitiveType {
|
||||
// don't change the enums values (made to match GL)
|
||||
POINTS, //!< points
|
||||
LINES, //!< lines
|
||||
UNUSED1,
|
||||
LINE_STRIP, //!< line strip
|
||||
TRIANGLES, //!< triangles
|
||||
TRIANGLE_STRIP, //!< triangle strip
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
enum ShadowType {
|
||||
PCF, //!< percentage-closer filtered shadows (default)
|
||||
VSM, //!< variance shadows
|
||||
DPCF, //!< PCF with contact hardening simulation
|
||||
PCSS, //!< PCF with soft shadows and contact hardening
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
library shared_types;
|
||||
|
||||
export 'material.dart';
|
||||
export 'texture.dart';
|
||||
export 'entities.dart';
|
||||
export 'light.dart';
|
||||
export 'shadow.dart';
|
||||
export 'manipulator.dart';
|
||||
export 'pick_result.dart';
|
||||
export 'primitive.dart';
|
||||
export 'texture_details.dart';
|
||||
export 'tone_mapper.dart';
|
||||
@@ -0,0 +1,3 @@
|
||||
abstract class ThermionTexture {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
///
|
||||
/// This represents the backing "surface" that we render into.
|
||||
/// "Texture" here is a misnomer as it is only a render target texture on certain platforms.
|
||||
///
|
||||
class TextureDetails {
|
||||
final int textureId;
|
||||
|
||||
// both width and height are in physical, not logical pixels
|
||||
final int width;
|
||||
final int height;
|
||||
|
||||
TextureDetails(
|
||||
{required this.textureId, required this.width, required this.height});
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
enum ToneMapper { ACES, FILMIC, LINEAR }
|
||||
963
thermion_dart/lib/thermion_dart/viewer/thermion_viewer_base.dart
Normal file
963
thermion_dart/lib/thermion_dart/viewer/thermion_viewer_base.dart
Normal file
@@ -0,0 +1,963 @@
|
||||
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||
|
||||
import 'shared_types/shared_types.dart';
|
||||
export 'shared_types/shared_types.dart';
|
||||
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
const double kNear = 0.05;
|
||||
const double kFar = 1000.0;
|
||||
const double kFocalLength = 28.0;
|
||||
|
||||
abstract class ThermionViewer {
|
||||
///
|
||||
/// A Future that resolves when the underlying rendering context has been successfully created.
|
||||
///
|
||||
Future<bool> get initialized;
|
||||
|
||||
///
|
||||
/// The current dimensions of the viewport (in physical pixels).
|
||||
///
|
||||
var viewportDimensions = (0.0, 0.0);
|
||||
|
||||
///
|
||||
/// The current ratio of logical to physical pixels.
|
||||
///
|
||||
late double pixelRatio;
|
||||
|
||||
///
|
||||
/// The result(s) of calling [pick] (see below).
|
||||
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
||||
/// If [pick] is called without an active subscription to this stream, the results will be silently discarded.
|
||||
///
|
||||
Stream<FilamentPickResult> get pickResult;
|
||||
|
||||
///
|
||||
/// The result(s) of calling [pickGizmo] (see below).
|
||||
///
|
||||
Stream<FilamentPickResult> get gizmoPickResult;
|
||||
|
||||
///
|
||||
/// A Stream containing entities added/removed to/from to the scene.
|
||||
///
|
||||
Stream<SceneUpdateEvent> get sceneUpdated;
|
||||
|
||||
///
|
||||
/// Whether the controller is currently rendering at [framerate].
|
||||
///
|
||||
bool get rendering;
|
||||
|
||||
///
|
||||
/// Set to true to continuously render the scene at the framerate specified by [setFrameRate] (60 fps by default).
|
||||
///
|
||||
Future setRendering(bool render);
|
||||
|
||||
///
|
||||
/// Render a single frame immediately.
|
||||
///
|
||||
Future render();
|
||||
|
||||
///
|
||||
/// Requests a single frame to be rendered. This is only intended to be used internally.
|
||||
///
|
||||
void requestFrame();
|
||||
|
||||
///
|
||||
/// Render a single frame and copy the pixel buffer to [out].
|
||||
///
|
||||
Future<Uint8List> capture();
|
||||
|
||||
///
|
||||
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
|
||||
///
|
||||
Future setFrameRate(int framerate);
|
||||
|
||||
///
|
||||
/// Destroys/disposes the viewer (including the entire scene). You cannot use the viewer after calling this method.
|
||||
///
|
||||
Future dispose();
|
||||
|
||||
///
|
||||
/// Set the background image to [path] (which should have a file extension .png, .jpg, or .ktx).
|
||||
/// This will be rendered at the maximum depth (i.e. behind all other objects including the skybox).
|
||||
/// If [fillHeight] is false, the image will be rendered at its original size. Note this may cause issues with pixel density so be sure to specify the correct resolution
|
||||
/// If [fillHeight] is true, the image will be stretched/compressed to fit the height of the viewport.
|
||||
///
|
||||
Future setBackgroundImage(String path, {bool fillHeight = false});
|
||||
|
||||
///
|
||||
/// Moves the background image to the relative offset from the origin (bottom-left) specified by [x] and [y].
|
||||
/// If [clamp] is true, the image cannot be positioned outside the bounds of the viewport.
|
||||
///
|
||||
Future setBackgroundImagePosition(double x, double y, {bool clamp = false});
|
||||
|
||||
///
|
||||
/// Removes the background image.
|
||||
///
|
||||
Future clearBackgroundImage();
|
||||
|
||||
///
|
||||
/// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox).
|
||||
///
|
||||
Future setBackgroundColor(double r, double g, double b, double alpha);
|
||||
|
||||
///
|
||||
/// Load a skybox from [skyboxPath] (which must be a .ktx file)
|
||||
///
|
||||
Future loadSkybox(String skyboxPath);
|
||||
|
||||
///
|
||||
/// Removes the skybox from the scene.
|
||||
///
|
||||
Future removeSkybox();
|
||||
|
||||
///
|
||||
/// Creates an indirect light by loading the reflections/irradiance from the KTX file.
|
||||
/// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced.
|
||||
///
|
||||
Future loadIbl(String lightingPath, {double intensity = 30000});
|
||||
|
||||
///
|
||||
/// Creates a indirect light with the given color.
|
||||
/// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced.
|
||||
///
|
||||
Future createIbl(double r, double g, double b, double intensity);
|
||||
|
||||
///
|
||||
/// Rotates the IBL & skybox.
|
||||
///
|
||||
Future rotateIbl(Matrix3 rotation);
|
||||
|
||||
///
|
||||
/// Removes the image-based light from the scene.
|
||||
///
|
||||
Future removeIbl();
|
||||
|
||||
///
|
||||
/// Add a light to the scene.
|
||||
/// See LightManager.h for details
|
||||
/// Note that [sunAngularRadius] is in degrees,
|
||||
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
|
||||
///
|
||||
@Deprecated(
|
||||
"This will be removed in future versions. Use addDirectLight instead.")
|
||||
Future<ThermionEntity> addLight(
|
||||
LightType type,
|
||||
double colour,
|
||||
double intensity,
|
||||
double posX,
|
||||
double posY,
|
||||
double posZ,
|
||||
double dirX,
|
||||
double dirY,
|
||||
double dirZ,
|
||||
{double falloffRadius = 1.0,
|
||||
double spotLightConeInner = pi / 8,
|
||||
double spotLightConeOuter = pi / 4,
|
||||
double sunAngularRadius = 0.545,
|
||||
double sunHaloSize = 10.0,
|
||||
double sunHaloFallof = 80.0,
|
||||
bool castShadows = true});
|
||||
|
||||
///
|
||||
/// Adds a direct light to the scene.
|
||||
/// See LightManager.h for details
|
||||
/// Note that [sunAngularRadius] is in degrees,
|
||||
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
|
||||
///
|
||||
Future<ThermionEntity> addDirectLight(DirectLight light);
|
||||
|
||||
///
|
||||
/// Remove a light from the scene.
|
||||
///
|
||||
Future removeLight(ThermionEntity light);
|
||||
|
||||
///
|
||||
/// Remove all lights (excluding IBL) from the scene.
|
||||
///
|
||||
Future clearLights();
|
||||
|
||||
///
|
||||
/// Load the .glb asset at the given path and insert into the scene.
|
||||
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
|
||||
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
|
||||
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
|
||||
///
|
||||
Future<ThermionEntity> loadGlb(String path,
|
||||
{int numInstances = 1, bool keepData = false});
|
||||
|
||||
///
|
||||
/// Load the .glb asset from the specified buffer and insert into the scene.
|
||||
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
|
||||
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
|
||||
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
|
||||
///
|
||||
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data,
|
||||
{int numInstances = 1,
|
||||
bool keepData = false,
|
||||
int priority = 4,
|
||||
int layer = 0});
|
||||
|
||||
///
|
||||
/// Create a new instance of [entity].
|
||||
///
|
||||
Future<ThermionEntity> createInstance(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns the number of instances of the asset associated with [entity].
|
||||
///
|
||||
Future<int> getInstanceCount(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns all instances of [entity].
|
||||
///
|
||||
Future<List<ThermionEntity>> getInstances(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Load the .gltf asset at the given path and insert into the scene.
|
||||
/// [relativeResourcePath] is the folder path where the glTF resources are stored;
|
||||
/// this is usually the parent directory of the .gltf file itself.
|
||||
///
|
||||
/// See [loadGlb] for an explanation of [keepData].
|
||||
///
|
||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||
{bool keepData = false});
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panStart(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panUpdate(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panEnd();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateStart(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateUpdate(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateEnd();
|
||||
|
||||
///
|
||||
/// Set the weights for all morph targets in [entity] to [weights].
|
||||
/// Note that [weights] must contain values for ALL morph targets, but no exception will be thrown if you don't do so (you'll just get incorrect results).
|
||||
/// If you only want to set one value, set all others to zero (check [getMorphTargetNames] if you need the get a list of all morph targets).
|
||||
/// IMPORTANT - this accepts the actual ThermionEntity with the relevant morph targets (unlike [getMorphTargetNames], which uses the parent entity and the child mesh name).
|
||||
/// Use [getChildEntityByName] if you are setting the weights for a child mesh.
|
||||
///
|
||||
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights);
|
||||
|
||||
///
|
||||
/// Gets the names of all morph targets for the child renderable [childEntity] under [entity].
|
||||
///
|
||||
Future<List<String>> getMorphTargetNames(
|
||||
ThermionEntity entity, ThermionEntity childEntity);
|
||||
|
||||
///
|
||||
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
|
||||
///
|
||||
Future<List<String>> getBoneNames(ThermionEntity entity, {int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Gets the names of all glTF animations embedded in the specified entity.
|
||||
///
|
||||
Future<List<String>> getAnimationNames(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Returns the length (in seconds) of the animation at the given index.
|
||||
///
|
||||
Future<double> getAnimationDuration(
|
||||
ThermionEntity entity, int animationIndex);
|
||||
|
||||
///
|
||||
/// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
|
||||
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
|
||||
/// throwing an exception if any cannot be found.
|
||||
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
|
||||
///
|
||||
Future setMorphAnimationData(
|
||||
ThermionEntity entity, MorphAnimationData animation,
|
||||
{List<String>? targetMeshNames});
|
||||
|
||||
///
|
||||
/// Clear all current morph animations for [entity].
|
||||
///
|
||||
Future clearMorphAnimationData(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Resets all bones in the given entity to their rest pose.
|
||||
/// This should be done before every call to addBoneAnimation.
|
||||
///
|
||||
Future resetBones(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Enqueues and plays the [animation] for the specified bone(s).
|
||||
/// By default, frame data is interpreted as being in *parent* bone space;
|
||||
/// a 45 degree around Y means the bone will rotate 45 degrees around the
|
||||
/// Y axis of the parent bone *in its current orientation*.
|
||||
/// (i.e NOT the parent bone's rest position!).
|
||||
/// Currently, only [Space.ParentBone] and [Space.Model] are supported; if you want
|
||||
/// to transform to another space, you will need to do so manually.
|
||||
///
|
||||
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
|
||||
/// the current active glTF animation ("animation1") and the animation you
|
||||
/// set via this method ("animation2"). The bone orientations will be
|
||||
/// linearly interpolated between animation1 and animation2; at time 0,
|
||||
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
|
||||
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
|
||||
/// This will be applied in reverse after [fadeOutInSecs].
|
||||
///
|
||||
///
|
||||
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
||||
{int skinIndex = 0,
|
||||
double fadeInInSecs = 0.0,
|
||||
double fadeOutInSecs = 0.0,
|
||||
double maxDelta = 1.0});
|
||||
|
||||
///
|
||||
/// Gets the entity representing the bone at [boneIndex]/[skinIndex].
|
||||
/// The returned entity is only intended for use with [getWorldTransform].
|
||||
///
|
||||
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Gets the local (relative to parent) transform for [entity].
|
||||
///
|
||||
Future<Matrix4> getLocalTransform(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Gets the world transform for [entity].
|
||||
///
|
||||
Future<Matrix4> getWorldTransform(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Gets the inverse bind (pose) matrix for the bone.
|
||||
/// Note that [parent] must be the ThermionEntity returned by [loadGlb/loadGltf], not any other method ([getChildEntity] etc).
|
||||
/// This is because all joint information is internally stored with the parent entity.
|
||||
///
|
||||
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Sets the transform (relative to its parent) for [entity].
|
||||
///
|
||||
Future setTransform(ThermionEntity entity, Matrix4 transform);
|
||||
|
||||
///
|
||||
/// Updates the bone matrices for [entity] (which must be the ThermionEntity
|
||||
/// returned by [loadGlb/loadGltf]).
|
||||
/// Under the hood, this just calls [updateBoneMatrices] on the Animator
|
||||
/// instance of the relevant FilamentInstance (which uses the local
|
||||
/// bone transform and the inverse bind matrix to set the bone matrix).
|
||||
///
|
||||
Future updateBoneMatrices(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Directly set the bone matrix for the bone at the given index.
|
||||
/// Don't call this manually unless you know what you're doing.
|
||||
///
|
||||
Future setBoneTransform(
|
||||
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
||||
{int skinIndex = 0});
|
||||
|
||||
///
|
||||
/// Removes/destroys the specified entity from the scene.
|
||||
/// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete.
|
||||
///
|
||||
Future removeEntity(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Removes/destroys all renderable entities from the scene (including cameras).
|
||||
/// All [ThermionEntity] handles will no longer be valid after this method is called; ensure you immediately discard all references to all entities once this method is complete.
|
||||
///
|
||||
Future clearEntities();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomBegin();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomUpdate(double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomEnd();
|
||||
|
||||
///
|
||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||
///
|
||||
Future playAnimation(ThermionEntity entity, int index,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0,
|
||||
double startOffset = 0.0});
|
||||
|
||||
///
|
||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||
///
|
||||
Future playAnimationByName(ThermionEntity entity, String name,
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0});
|
||||
|
||||
Future setAnimationFrame(
|
||||
ThermionEntity entity, int index, int animationFrame);
|
||||
|
||||
Future stopAnimation(ThermionEntity entity, int animationIndex);
|
||||
Future stopAnimationByName(ThermionEntity entity, String name);
|
||||
|
||||
///
|
||||
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
||||
///
|
||||
Future setCamera(ThermionEntity entity, String? name);
|
||||
|
||||
///
|
||||
/// Sets the current scene camera to the main camera (which is always available and added to every scene by default).
|
||||
///
|
||||
Future setMainCamera();
|
||||
|
||||
///
|
||||
/// Returns the entity associated with the main camera. You probably never need this; use getMainCamera instead.
|
||||
///
|
||||
Future<ThermionEntity> getMainCameraEntity();
|
||||
|
||||
///
|
||||
/// Returns the entity associated with the main camera. You probably never need this; use getMainCamera instead.
|
||||
///
|
||||
Future<Camera> getMainCamera();
|
||||
|
||||
///
|
||||
/// Sets the horizontal field of view (if [horizontal] is true) or vertical field of view for the currently active camera to [degrees].
|
||||
/// The aspect ratio of the current viewport is used.
|
||||
///
|
||||
Future setCameraFov(double degrees, {bool horizontal = true});
|
||||
|
||||
///
|
||||
/// Gets the field of view (in degrees).
|
||||
///
|
||||
Future<double> getCameraFov(bool horizontal);
|
||||
|
||||
///
|
||||
/// Sets the tone mapping (requires postprocessing).
|
||||
///
|
||||
Future setToneMapping(ToneMapper mapper);
|
||||
|
||||
///
|
||||
/// Sets the strength of the bloom.
|
||||
///
|
||||
Future setBloom(double bloom);
|
||||
|
||||
///
|
||||
/// Sets the focal length of the camera. Default value is 28.0.
|
||||
///
|
||||
Future setCameraFocalLength(double focalLength);
|
||||
|
||||
///
|
||||
/// Sets the distance (in world units) to the near/far planes for the active camera. Default values are 0.05/1000.0. See Camera.h for details.
|
||||
///
|
||||
Future setCameraCulling(double near, double far);
|
||||
|
||||
///
|
||||
/// Get the distance (in world units) to the near plane for the active camera.
|
||||
///
|
||||
@Deprecated("Use getCameraNear")
|
||||
Future<double> getCameraCullingNear();
|
||||
|
||||
///
|
||||
/// Get the distance (in world units) to the near plane for the active camera.
|
||||
///
|
||||
Future<double> getCameraNear();
|
||||
|
||||
///
|
||||
/// Get the distance (in world units) to the far culling plane for the active camera.
|
||||
///
|
||||
Future<double> getCameraCullingFar();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setCameraLensProjection(
|
||||
{double near = kNear,
|
||||
double far = kFar,
|
||||
double? aspect,
|
||||
double focalLength = kFocalLength});
|
||||
|
||||
///
|
||||
/// Sets the focus distance for the camera.
|
||||
///
|
||||
Future setCameraFocusDistance(double focusDistance);
|
||||
|
||||
///
|
||||
/// Get the camera position in world space.
|
||||
///
|
||||
Future<Vector3> getCameraPosition();
|
||||
|
||||
///
|
||||
/// Get the camera's model matrix.
|
||||
///
|
||||
Future<Matrix4> getCameraModelMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's view matrix. See Camera.h for more details.
|
||||
///
|
||||
Future<Matrix4> getCameraViewMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's projection matrix. See Camera.h for more details.
|
||||
///
|
||||
Future<Matrix4> getCameraProjectionMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's culling projection matrix. See Camera.h for more details.
|
||||
///
|
||||
Future<Matrix4> getCameraCullingProjectionMatrix();
|
||||
|
||||
///
|
||||
/// Get the camera's culling frustum in world space. Returns a (vector_math) [Frustum] instance where plane0-plane6 define the left, right, bottom, top, far and near planes respectively.
|
||||
/// See Camera.h and (filament) Frustum.h for more details.
|
||||
///
|
||||
Future<Frustum> getCameraFrustum();
|
||||
|
||||
///
|
||||
/// Set the camera position in world space. Note this is not persistent - any viewport navigation will reset the camera transform.
|
||||
///
|
||||
Future setCameraPosition(double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Get the camera rotation matrix.
|
||||
///
|
||||
Future<Matrix3> getCameraRotation();
|
||||
|
||||
///
|
||||
/// Repositions the camera to the last vertex of the bounding box of [entity], looking at the penultimate vertex.
|
||||
///
|
||||
Future moveCameraToAsset(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Enables/disables frustum culling.
|
||||
///
|
||||
Future setViewFrustumCulling(bool enabled);
|
||||
|
||||
///
|
||||
/// Sets the camera exposure.
|
||||
///
|
||||
Future setCameraExposure(
|
||||
double aperture, double shutterSpeed, double sensitivity);
|
||||
|
||||
///
|
||||
/// Rotate the camera by [rads] around the given axis.
|
||||
///
|
||||
Future setCameraRotation(Quaternion quaternion);
|
||||
|
||||
///
|
||||
/// Sets the camera model matrix.
|
||||
///
|
||||
@Deprecated("Will be superseded by setCameraModelMatrix4")
|
||||
Future setCameraModelMatrix(List<double> matrix);
|
||||
|
||||
///
|
||||
/// Sets the camera model matrix.
|
||||
///
|
||||
Future setCameraModelMatrix4(Matrix4 matrix);
|
||||
|
||||
///
|
||||
/// Sets the `baseColorFactor` property for the material at index [materialIndex] in [entity] under node [meshName] to [color].
|
||||
///
|
||||
@Deprecated("Use setMaterialPropertyFloat4 instead")
|
||||
Future setMaterialColor(ThermionEntity entity, String meshName,
|
||||
int materialIndex, double r, double g, double b, double a);
|
||||
|
||||
///
|
||||
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
|
||||
/// [entity] must have a Renderable attached.
|
||||
///
|
||||
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName,
|
||||
int materialIndex, double f1, double f2, double f3, double f4);
|
||||
|
||||
///
|
||||
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
|
||||
/// [entity] must have a Renderable attached.
|
||||
///
|
||||
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName,
|
||||
int materialIndex, double value);
|
||||
|
||||
///
|
||||
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
|
||||
/// [entity] must have a Renderable attached.
|
||||
///
|
||||
Future setMaterialPropertyInt(
|
||||
ThermionEntity entity, String propertyName, int materialIndex, int value);
|
||||
|
||||
///
|
||||
/// Scale [entity] to fit within the unit cube.
|
||||
///
|
||||
Future transformToUnitCube(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Directly sets the world space position for [entity] to the given coordinates.
|
||||
///
|
||||
Future setPosition(ThermionEntity entity, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Set the world space position for [lightEntity] to the given coordinates.
|
||||
///
|
||||
Future setLightPosition(
|
||||
ThermionEntity lightEntity, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Sets the world space direction for [lightEntity] to the given vector.
|
||||
///
|
||||
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction);
|
||||
|
||||
///
|
||||
/// Directly sets the scale for [entity], skipping all collision detection.
|
||||
///
|
||||
Future setScale(ThermionEntity entity, double scale);
|
||||
|
||||
///
|
||||
/// Directly sets the rotation for [entity] to [rads] around the axis {x,y,z}, skipping all collision detection.
|
||||
///
|
||||
Future setRotation(
|
||||
ThermionEntity entity, double rads, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Queues an update to the worldspace position for [entity] to {x,y,z}.
|
||||
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
||||
///
|
||||
Future queuePositionUpdate(
|
||||
ThermionEntity entity, double x, double y, double z,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// TODO
|
||||
///
|
||||
Future queuePositionUpdateFromViewportCoords(
|
||||
ThermionEntity entity, double x, double y);
|
||||
|
||||
///
|
||||
/// TODO
|
||||
///
|
||||
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity,
|
||||
double viewportX, double viewportY, double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Queues an update to the worldspace rotation for [entity].
|
||||
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
||||
///
|
||||
Future queueRotationUpdate(
|
||||
ThermionEntity entity, double rads, double x, double y, double z,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Same as [queueRotationUpdate].
|
||||
///
|
||||
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
|
||||
{bool relative = false});
|
||||
|
||||
///
|
||||
/// Enable/disable postprocessing (disabled by default).
|
||||
///
|
||||
Future setPostProcessing(bool enabled);
|
||||
|
||||
///
|
||||
/// Enable/disable shadows (disabled by default).
|
||||
///
|
||||
Future setShadowsEnabled(bool enabled);
|
||||
|
||||
///
|
||||
/// Set shadow type.
|
||||
///
|
||||
Future setShadowType(ShadowType shadowType);
|
||||
|
||||
///
|
||||
/// Set soft shadow options (ShadowType DPCF and PCSS)
|
||||
///
|
||||
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale);
|
||||
|
||||
///
|
||||
/// Set antialiasing options.
|
||||
///
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
||||
|
||||
///
|
||||
/// Sets the rotation for [entity] to the specified quaternion.
|
||||
///
|
||||
Future setRotationQuat(ThermionEntity entity, Quaternion rotation);
|
||||
|
||||
///
|
||||
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
|
||||
///
|
||||
Future reveal(ThermionEntity entity, String? meshName);
|
||||
|
||||
///
|
||||
/// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity].
|
||||
/// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering.
|
||||
///
|
||||
Future hide(ThermionEntity entity, String? meshName);
|
||||
|
||||
///
|
||||
/// Used to select the entity in the scene at the given viewport coordinates.
|
||||
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
|
||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||
///
|
||||
void pick(int x, int y);
|
||||
|
||||
///
|
||||
/// Used to test whether a Gizmo is at the given viewport coordinates.
|
||||
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method.
|
||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||
///
|
||||
void pickGizmo(int x, int y);
|
||||
|
||||
///
|
||||
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
|
||||
///
|
||||
String? getNameForEntity(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Sets the options for manipulating the camera via the viewport.
|
||||
/// ManipulatorMode.FREE_FLIGHT and ManipulatorMode.MAP are currently unsupported and will throw an exception.
|
||||
///
|
||||
@Deprecated("Use ThermionGestureHandler instead")
|
||||
Future setCameraManipulatorOptions(
|
||||
{ManipulatorMode mode = ManipulatorMode.ORBIT,
|
||||
double orbitSpeedX = 0.01,
|
||||
double orbitSpeedY = 0.01,
|
||||
double zoomSpeed = 0.01});
|
||||
|
||||
///
|
||||
/// Returns all child entities under [parent].
|
||||
///
|
||||
Future<List<ThermionEntity>> getChildEntities(
|
||||
ThermionEntity parent, bool renderableOnly);
|
||||
|
||||
///
|
||||
/// Finds the child entity named [childName] associated with the given parent.
|
||||
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
|
||||
///
|
||||
Future<ThermionEntity> getChildEntity(
|
||||
ThermionEntity parent, String childName);
|
||||
|
||||
///
|
||||
/// List the name of all child entities under the given entity.
|
||||
///
|
||||
Future<List<String>> getChildEntityNames(ThermionEntity entity,
|
||||
{bool renderableOnly = true});
|
||||
|
||||
///
|
||||
/// If [recording] is set to true, each frame the framebuffer/texture will be written to /tmp/output_*.png.
|
||||
/// This will impact performance; handle with care.
|
||||
///
|
||||
Future setRecording(bool recording);
|
||||
|
||||
///
|
||||
/// Sets the output directory where recorded PNGs will be placed.
|
||||
///
|
||||
Future setRecordingOutputDirectory(String outputDirectory);
|
||||
|
||||
///
|
||||
/// An [entity] will only be animatable after an animation component is attached.
|
||||
/// Any calls to [playAnimation]/[setBoneAnimation]/[setMorphAnimation] will have no visual effect until [addAnimationComponent] has been called on the instance.
|
||||
///
|
||||
Future addAnimationComponent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Removes an animation component from [entity].
|
||||
///
|
||||
Future removeAnimationComponent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Makes [entity] collidable.
|
||||
/// This allows you to call [testCollisions] with any other entity ("entity B") to see if [entity] has collided with entity B. The callback will be invoked if so.
|
||||
/// Alternatively, if [affectsTransform] is true and this entity collides with another entity, any queued position updates to the latter entity will be ignored.
|
||||
///
|
||||
Future addCollisionComponent(ThermionEntity entity,
|
||||
{void Function(int entityId1, int entityId2)? callback,
|
||||
bool affectsTransform = false});
|
||||
|
||||
///
|
||||
/// Removes the collision component from [entity], meaning this will no longer be tested when [testCollisions] or [queuePositionUpdate] is called with another entity.
|
||||
///
|
||||
Future removeCollisionComponent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Creates a (renderable) entity with the specified geometry and adds to the scene.
|
||||
/// If [keepData] is true, the source data will not be released.
|
||||
///
|
||||
Future createGeometry(Geometry geometry,
|
||||
{MaterialInstance? materialInstance, bool keepData = false});
|
||||
|
||||
///
|
||||
/// Gets the parent entity of [entity]. Returns null if the entity has no parent.
|
||||
///
|
||||
Future<ThermionEntity?> getParent(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Gets the ancestor (ultimate parent) entity of [entity]. Returns null if the entity has no parent.
|
||||
///
|
||||
Future<ThermionEntity?> getAncestor(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Sets the parent transform of [child] to [parent].
|
||||
///
|
||||
Future setParent(ThermionEntity child, ThermionEntity parent,
|
||||
{bool preserveScaling});
|
||||
|
||||
///
|
||||
/// Test all collidable entities against this entity to see if any have collided.
|
||||
/// This method returns void; the relevant callback passed to [addCollisionComponent] will be fired if a collision is detected.
|
||||
///
|
||||
Future testCollisions(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
|
||||
///
|
||||
Future setPriority(ThermionEntity entityId, int priority);
|
||||
|
||||
///
|
||||
/// The gizmo for translating/rotating objects. Only one gizmo is present in the scene.
|
||||
///
|
||||
AbstractGizmo? get gizmo;
|
||||
|
||||
///
|
||||
/// Register a callback to be invoked when this viewer is disposed.
|
||||
///
|
||||
void onDispose(Future Function() callback);
|
||||
|
||||
///
|
||||
/// Gets the 2D bounding box (in viewport coordinates) for the given entity.
|
||||
///
|
||||
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Filament assigns renderables to a numeric layer.
|
||||
/// We place all scene assets in layer 0 (enabled by default), gizmos in layer 1 (enabled by default), world grid in layer 2 (disabled by default).
|
||||
/// Use this method to toggle visibility of the respective layer.
|
||||
///
|
||||
Future setLayerVisibility(int layer, bool visible);
|
||||
|
||||
///
|
||||
/// Assigns [entity] to visibility layer [layer].
|
||||
///
|
||||
Future setVisibilityLayer(ThermionEntity entity, int layer);
|
||||
|
||||
///
|
||||
/// Show/hide the translation gizmo.
|
||||
///
|
||||
Future setGizmoVisibility(bool visible);
|
||||
|
||||
///
|
||||
/// Renders an outline around [entity] with the given color.
|
||||
///
|
||||
Future setStencilHighlight(ThermionEntity entity,
|
||||
{double r = 1.0, double g = 0.0, double b = 0.0});
|
||||
|
||||
///
|
||||
/// Removes the outline around [entity]. Noop if there was no highlight.
|
||||
///
|
||||
Future removeStencilHighlight(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Decodes the specified image data and creates a texture.
|
||||
///
|
||||
Future<ThermionTexture> createTexture(Uint8List data);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity,
|
||||
{int materialIndex = 0, String parameterName = "baseColorMap"});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroyTexture(covariant ThermionTexture texture);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> createUbershaderMaterialInstance({
|
||||
bool doubleSided = false,
|
||||
bool unlit = false,
|
||||
bool hasVertexColors = false,
|
||||
bool hasBaseColorTexture = false,
|
||||
bool hasNormalTexture = false,
|
||||
bool hasOcclusionTexture = false,
|
||||
bool hasEmissiveTexture = false,
|
||||
bool useSpecularGlossiness = false,
|
||||
AlphaMode alphaMode = AlphaMode.OPAQUE,
|
||||
bool enableDiagnostics = false,
|
||||
bool hasMetallicRoughnessTexture = false,
|
||||
int metallicRoughnessUV = 0,
|
||||
int baseColorUV = 0,
|
||||
bool hasClearCoatTexture = false,
|
||||
int clearCoatUV = 0,
|
||||
bool hasClearCoatRoughnessTexture = false,
|
||||
int clearCoatRoughnessUV = 0,
|
||||
bool hasClearCoatNormalTexture = false,
|
||||
int clearCoatNormalUV = 0,
|
||||
bool hasClearCoat = false,
|
||||
bool hasTransmission = false,
|
||||
bool hasTextureTransforms = false,
|
||||
int emissiveUV = 0,
|
||||
int aoUV = 0,
|
||||
int normalUV = 0,
|
||||
bool hasTransmissionTexture = false,
|
||||
int transmissionUV = 0,
|
||||
bool hasSheenColorTexture = false,
|
||||
int sheenColorUV = 0,
|
||||
bool hasSheenRoughnessTexture = false,
|
||||
int sheenRoughnessUV = 0,
|
||||
bool hasVolumeThicknessTexture = false,
|
||||
int volumeThicknessUV = 0,
|
||||
bool hasSheen = false,
|
||||
bool hasIOR = false,
|
||||
bool hasVolume = false,
|
||||
});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroyMaterialInstance(covariant MaterialInstance materialInstance);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> createUnlitMaterialInstance();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance?> getMaterialInstanceAt(
|
||||
ThermionEntity entity, int index);
|
||||
}
|
||||
@@ -1,13 +1,15 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
typedef ThermionViewerImpl = ThermionViewerStub;
|
||||
|
||||
class ThermionViewerStub extends ThermionViewer {
|
||||
@override
|
||||
Future addAnimationComponent(ThermionEntity entity) {
|
||||
@@ -73,13 +75,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future createGeometry(List<double> vertices, List<int> indices,
|
||||
{String? materialPath,
|
||||
PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) {
|
||||
// TODO: implement createGeometry
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> createInstance(ThermionEntity entity) {
|
||||
@@ -220,12 +215,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> getMainCamera() {
|
||||
// TODO: implement getMainCamera
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getMorphTargetNames(
|
||||
ThermionEntity entity, ThermionEntity childEntity) {
|
||||
@@ -265,19 +254,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
// TODO: implement initialized
|
||||
Future<bool> get initialized => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1}) {
|
||||
// TODO: implement loadGlb
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||
{bool force = false}) {
|
||||
// TODO: implement loadGltf
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future loadIbl(String lightingPath, {double intensity = 30000}) {
|
||||
// TODO: implement loadIbl
|
||||
@@ -333,7 +309,8 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0}) {
|
||||
double crossfade = 0.0,
|
||||
double startOffset=0.0}) {
|
||||
// TODO: implement playAnimation
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@@ -453,10 +430,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement scene
|
||||
Scene get scene => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future setAnimationFrame(
|
||||
ThermionEntity entity, int index, int animationFrame) {
|
||||
@@ -534,7 +507,7 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
}
|
||||
|
||||
@override
|
||||
Future setCameraFov(double degrees, double width, double height) {
|
||||
Future setCameraFov(double degrees, {bool horizontal=true}) {
|
||||
// TODO: implement setCameraFov
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@@ -586,6 +559,11 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future clearMorphAnimationData(ThermionEntity entity) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMorphAnimationData(
|
||||
ThermionEntity entity, MorphAnimationData animation,
|
||||
@@ -601,7 +579,7 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParent(ThermionEntity child, ThermionEntity parent) {
|
||||
Future setParent(ThermionEntity child, ThermionEntity parent, { bool preserveScaling = false}) {
|
||||
// TODO: implement setParent
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@@ -726,22 +704,267 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
// TODO: implement zoomUpdate
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setShadowType(ShadowType shadowType) {
|
||||
// TODO: implement setShadowType
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setShadowsEnabled(bool enabled) {
|
||||
// TODO: implement setShadowsEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) {
|
||||
// TODO: implement setSoftShadowOptions
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> capture() {
|
||||
// TODO: implement capture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Aabb2> getBoundingBox(ThermionEntity entity) {
|
||||
// TODO: implement getBoundingBox
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getCameraFov(bool horizontal) {
|
||||
// TODO: implement getCameraFov
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity, double viewportX, double viewportY, double x, double y, double z) {
|
||||
// TODO: implement queueRelativePositionUpdateWorldAxis
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLayerEnabled(int layer, bool enabled) {
|
||||
// TODO: implement setLayerEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future createIbl(double r, double g, double b, double intensity) {
|
||||
// TODO: implement createIbl
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement gizmoPickResult
|
||||
Stream<FilamentPickResult> get gizmoPickResult => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void pickGizmo(int x, int y) {
|
||||
// TODO: implement pickGizmo
|
||||
}
|
||||
|
||||
@override
|
||||
Future setGizmoVisibility(bool visible) {
|
||||
// TODO: implement setGizmoVisibility
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity?> getAncestor(ThermionEntity entity) {
|
||||
// TODO: implement getAncestor
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future queuePositionUpdateFromViewportCoords(ThermionEntity entity, double x, double y) {
|
||||
// TODO: implement queuePositionUpdateFromViewportCoords
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future removeStencilHighlight(ThermionEntity entity) {
|
||||
// TODO: implement removeStencilHighlight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) {
|
||||
// TODO: implement setLightDirection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLightPosition(ThermionEntity lightEntity, double x, double y, double z) {
|
||||
// TODO: implement setLightPosition
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) {
|
||||
// TODO: implement setStencilHighlight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getCameraNear() {
|
||||
// TODO: implement getCameraNear
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity) {
|
||||
// TODO: implement getViewportBoundingBox
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setCameraModelMatrix4(Matrix4 matrix) {
|
||||
// TODO: implement setCameraModelMatrix4
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1, bool keepData = false}) {
|
||||
// TODO: implement loadGlb
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath, {bool keepData = false}) {
|
||||
// TODO: implement loadGltf
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) {
|
||||
// TODO: implement setMaterialPropertyFloat
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, int materialIndex, double f1, double f2, double f3, double f4) {
|
||||
// TODO: implement setMaterialPropertyFloat4
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement sceneUpdated
|
||||
Stream<SceneUpdateEvent> get sceneUpdated => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> addDirectLight(DirectLight light) {
|
||||
// TODO: implement addDirectLight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, {int materialIndex = 0, String parameterName = "baseColorMap"}) {
|
||||
// TODO: implement applyTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionTexture> createTexture(Uint8List data) {
|
||||
// TODO: implement createTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance> createUbershaderMaterialInstance({bool doubleSided = false, bool unlit = false, bool hasVertexColors = false, bool hasBaseColorTexture = false, bool hasNormalTexture = false, bool hasOcclusionTexture = false, bool hasEmissiveTexture = false, bool useSpecularGlossiness = false, AlphaMode alphaMode = AlphaMode.OPAQUE, bool enableDiagnostics = false, bool hasMetallicRoughnessTexture = false, int metallicRoughnessUV = 0, int baseColorUV = 0, bool hasClearCoatTexture = false, int clearCoatUV = 0, bool hasClearCoatRoughnessTexture = false, int clearCoatRoughnessUV = 0, bool hasClearCoatNormalTexture = false, int clearCoatNormalUV = 0, bool hasClearCoat = false, bool hasTransmission = false, bool hasTextureTransforms = false, int emissiveUV = 0, int aoUV = 0, int normalUV = 0, bool hasTransmissionTexture = false, int transmissionUV = 0, bool hasSheenColorTexture = false, int sheenColorUV = 0, bool hasSheenRoughnessTexture = false, int sheenRoughnessUV = 0, bool hasVolumeThicknessTexture = false, int volumeThicknessUV = 0, bool hasSheen = false, bool hasIOR = false, bool hasVolume = false}) {
|
||||
// TODO: implement createUbershaderMaterialInstance
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance> createUnlitMaterialInstance() {
|
||||
// TODO: implement createUnlitMaterialInstance
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroyMaterialInstance(covariant MaterialInstance materialInstance) {
|
||||
// TODO: implement destroyMaterialInstance
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroyTexture(covariant ThermionTexture texture) {
|
||||
// TODO: implement destroyTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future createGeometry(Geometry geometry, {MaterialInstance? materialInstance, bool keepData = false}) {
|
||||
// TODO: implement createGeometry
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0}) {
|
||||
// TODO: implement loadGlbFromBuffer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) {
|
||||
// TODO: implement setMaterialPropertyInt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance?> getMaterialInstanceAt(ThermionEntity entity, int index) {
|
||||
// TODO: implement getMaterialInstanceAt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLayerVisibility(int layer, bool visible) {
|
||||
// TODO: implement setLayerVisibility
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialDepthWrite(ThermionEntity entity, int materialIndex, bool enabled) {
|
||||
// TODO: implement setMaterialDepthWrite
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setVisibilityLayer(ThermionEntity entity, int layer) {
|
||||
// TODO: implement setVisibilityLayer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void requestFrame() {
|
||||
// TODO: implement requestFrame
|
||||
}
|
||||
|
||||
@override
|
||||
Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) {
|
||||
// TODO: implement setCameraLensProjection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> getMainCameraEntity() {
|
||||
// TODO: implement getMainCameraEntity
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Camera> getMainCamera() {
|
||||
// TODO: implement getMainCamera
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,7 +2,8 @@
|
||||
library thermion_flutter_js;
|
||||
|
||||
import 'dart:js_interop';
|
||||
import 'package:thermion_dart/thermion_dart/compatibility/web/interop/thermion_viewer_js_shim.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/web_js/src/thermion_viewer_js_shim.dart';
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart' as v64;
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
@@ -21,6 +22,7 @@ import 'package:vector_math/vector_math_64.dart';
|
||||
///
|
||||
@JSExport()
|
||||
class ThermionViewerJSDartBridge {
|
||||
final _logger = Logger("ThermionViewerJSDartBridge");
|
||||
final ThermionViewer viewer;
|
||||
|
||||
ThermionViewerJSDartBridge(this.viewer);
|
||||
@@ -46,6 +48,11 @@ class ThermionViewerJSDartBridge {
|
||||
@JSExport()
|
||||
JSPromise render() => viewer.render().toJS;
|
||||
|
||||
@JSExport()
|
||||
JSPromise<JSUint8Array> capture() {
|
||||
return viewer.capture().then((captured) => captured.toJS).toJS;
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setFrameRate(int framerate) => viewer.setFrameRate(framerate).toJS;
|
||||
|
||||
@@ -76,7 +83,7 @@ class ThermionViewerJSDartBridge {
|
||||
|
||||
@JSExport()
|
||||
JSPromise loadIbl(String lightingPath, double intensity) {
|
||||
print("Loading IBL from $lightingPath with intensity $intensity");
|
||||
_logger.info("Loading IBL from $lightingPath with intensity $intensity");
|
||||
return viewer.loadIbl(lightingPath, intensity: intensity).toJS;
|
||||
}
|
||||
|
||||
@@ -130,13 +137,13 @@ class ThermionViewerJSDartBridge {
|
||||
|
||||
@JSExport()
|
||||
JSPromise<JSNumber> loadGlb(String path, {int numInstances = 1}) {
|
||||
print("Loading GLB from path $path with numInstances $numInstances");
|
||||
_logger.info("Loading GLB from path $path with numInstances $numInstances");
|
||||
return viewer
|
||||
.loadGlb(path, numInstances: numInstances)
|
||||
.then((entity) => entity.toJS)
|
||||
.catchError((err) {
|
||||
print("Error: $err");
|
||||
}).toJS;
|
||||
_logger.info("Error: $err");
|
||||
}).toJS;
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
@@ -159,9 +166,9 @@ class ThermionViewerJSDartBridge {
|
||||
|
||||
@JSExport()
|
||||
JSPromise<JSNumber> loadGltf(String path, String relativeResourcePath,
|
||||
{bool force = false}) {
|
||||
{bool keepData = false}) {
|
||||
return viewer
|
||||
.loadGltf(path, relativeResourcePath, force: force)
|
||||
.loadGltf(path, relativeResourcePath, keepData: keepData)
|
||||
.then((entity) => entity.toJS)
|
||||
.toJS;
|
||||
}
|
||||
@@ -224,6 +231,11 @@ class ThermionViewerJSDartBridge {
|
||||
.then((v) => v.toJS)
|
||||
.toJS;
|
||||
|
||||
@JSExport()
|
||||
void clearMorphAnimationData(ThermionEntity entity) {
|
||||
viewer.clearMorphAnimationData(entity);
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setMorphAnimationData(
|
||||
ThermionEntity entity,
|
||||
@@ -253,13 +265,13 @@ class ThermionViewerJSDartBridge {
|
||||
targetMeshNames: targetMeshNamesDart,
|
||||
)
|
||||
.onError((err, st) {
|
||||
print("ERROR SETTING MORPH ANIMATION DATA : $err\n$st");
|
||||
_logger.severe("ERROR SETTING MORPH ANIMATION DATA : $err\n$st");
|
||||
return null;
|
||||
});
|
||||
return result.toJS;
|
||||
} catch (err, st) {
|
||||
print(err);
|
||||
print(st);
|
||||
_logger.severe(err);
|
||||
_logger.severe(st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -332,16 +344,15 @@ class ThermionViewerJSDartBridge {
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0}) =>
|
||||
double crossfade = 0.0,
|
||||
double startOffset = 0.0}) =>
|
||||
viewer
|
||||
.playAnimation(
|
||||
entity,
|
||||
index,
|
||||
loop: loop,
|
||||
reverse: reverse,
|
||||
replaceActive: replaceActive,
|
||||
crossfade: crossfade,
|
||||
)
|
||||
.playAnimation(entity, index,
|
||||
loop: loop,
|
||||
reverse: reverse,
|
||||
replaceActive: replaceActive,
|
||||
crossfade: crossfade,
|
||||
startOffset: startOffset)
|
||||
.toJS;
|
||||
|
||||
@JSExport()
|
||||
@@ -389,12 +400,21 @@ class ThermionViewerJSDartBridge {
|
||||
|
||||
@JSExport()
|
||||
JSPromise<JSNumber> getMainCamera() {
|
||||
return viewer.getMainCamera().then((camera) => camera.toJS).toJS;
|
||||
throw UnimplementedError("TODO");
|
||||
// return viewer.getMainCamera().then((camera) => camera.toJS).toJS;
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setCameraFov(double degrees, double width, double height) =>
|
||||
viewer.setCameraFov(degrees, width, height).toJS;
|
||||
JSPromise setParent(
|
||||
ThermionEntity child, ThermionEntity parent, bool preserveScaling) {
|
||||
return viewer
|
||||
.setParent(child, parent, preserveScaling: preserveScaling)
|
||||
.toJS;
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setCameraFov(double degrees, bool horizontal) =>
|
||||
viewer.setCameraFov(degrees, horizontal: horizontal).toJS;
|
||||
|
||||
@JSExport()
|
||||
JSPromise setToneMapping(int mapper) =>
|
||||
@@ -516,9 +536,11 @@ class ThermionViewerJSDartBridge {
|
||||
// b,
|
||||
// a,
|
||||
// ).toJS;
|
||||
|
||||
@JSExport()
|
||||
JSPromise transformToUnitCube(ThermionEntity entity) =>
|
||||
viewer.transformToUnitCube(entity).toJS;
|
||||
|
||||
@JSExport()
|
||||
JSPromise setPosition(ThermionEntity entity, double x, double y, double z) =>
|
||||
viewer.setPosition(entity, x, y, z).toJS;
|
||||
@@ -618,7 +640,7 @@ class ThermionViewerJSDartBridge {
|
||||
)
|
||||
.then((entities) => entities.map((entity) => entity.toJS).toList().toJS)
|
||||
.onError((e, st) async {
|
||||
print("Error : $e\n$st");
|
||||
_logger.severe("Error : $e\n$st");
|
||||
return <JSNumber>[].toJS;
|
||||
}).toJS;
|
||||
}
|
||||
@@ -632,7 +654,7 @@ class ThermionViewerJSDartBridge {
|
||||
)
|
||||
.then((entity) => entity.toJS)
|
||||
.onError((e, st) async {
|
||||
print("Error getChildEntity : $e\n$st");
|
||||
_logger.severe("Error getChildEntity : $e\n$st");
|
||||
return 0.toJS;
|
||||
}).toJS;
|
||||
}
|
||||
@@ -720,4 +742,20 @@ class ThermionViewerJSDartBridge {
|
||||
{JSFunction? callback, bool affectsTransform = false}) {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setShadowsEnabled(bool enabled) {
|
||||
return viewer.setShadowsEnabled(enabled).toJS;
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setShadowType(int shadowType) {
|
||||
return viewer.setShadowType(ShadowType.values[shadowType]).toJS;
|
||||
}
|
||||
|
||||
@JSExport()
|
||||
JSPromise setSoftShadowOptions(
|
||||
double penumbraScale, double penumbraRatioScale) {
|
||||
return viewer.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toJS;
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
import 'dart:js_interop';
|
||||
import 'dart:js_interop_unsafe';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart/scene_impl.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'thermion_viewer_js_shim.dart';
|
||||
|
||||
@@ -15,6 +19,7 @@ import 'thermion_viewer_js_shim.dart';
|
||||
/// a corresponding Javascript shim implementation (see [ThermionViewerJSShim]).
|
||||
///
|
||||
class ThermionViewerJS implements ThermionViewer {
|
||||
final _logger = Logger("ThermionViewerJS");
|
||||
late final ThermionViewerJSShim _shim;
|
||||
|
||||
ThermionViewerJS.fromGlobalProperty(String globalPropertyName) {
|
||||
@@ -163,9 +168,8 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1}) async {
|
||||
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1, bool keepData=false}) async {
|
||||
var entity = (await _shim.loadGlb(path, numInstances).toDart).toDartInt;
|
||||
scene.registerEntity(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -192,7 +196,7 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||
{bool force = false}) async {
|
||||
{bool keepData = false}) async {
|
||||
throw UnimplementedError();
|
||||
// final ThermionEntity jsEntity = await _shim
|
||||
// .loadGltf(path, relativeResourcePath, force: force)
|
||||
@@ -261,6 +265,11 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
.toDartDouble;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clearMorphAnimationData(ThermionEntity entity) async {
|
||||
_shim.clearMorphAnimationData(entity);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setMorphAnimationData(
|
||||
ThermionEntity entity, MorphAnimationData animation,
|
||||
@@ -282,8 +291,8 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
targetMeshNamesJS, animation.frameLengthInMs)
|
||||
.toDart;
|
||||
} catch (err, st) {
|
||||
print(err);
|
||||
print(st);
|
||||
_logger.severe(err);
|
||||
_logger.severe(st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
@@ -361,9 +370,11 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
{bool loop = false,
|
||||
bool reverse = false,
|
||||
bool replaceActive = true,
|
||||
double crossfade = 0.0}) async {
|
||||
double crossfade = 0.0,
|
||||
double startOffset = 0.0}) async {
|
||||
await _shim
|
||||
.playAnimation(entity, index, loop, reverse, replaceActive, crossfade)
|
||||
.playAnimation(
|
||||
entity, index, loop, reverse, replaceActive, crossfade, startOffset)
|
||||
.toDart;
|
||||
}
|
||||
|
||||
@@ -406,15 +417,15 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> getMainCamera() async {
|
||||
Future<Camera> getMainCamera() async {
|
||||
throw UnimplementedError();
|
||||
// final ThermionEntity jsEntity = await _shim.getMainCamera().toDart;
|
||||
// return ThermionEntity._fromJSObject(jsEntity).toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setCameraFov(double degrees, double width, double height) async {
|
||||
await _shim.setCameraFov(degrees, width, height).toDart;
|
||||
Future<void> setCameraFov(double degrees, {bool horizontal = true}) async {
|
||||
await _shim.setCameraFov(degrees, horizontal).toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -715,8 +726,9 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> createGeometry(
|
||||
List<double> vertices, List<int> indices,
|
||||
{String? materialPath,
|
||||
Geometry geometry,
|
||||
{
|
||||
bool keepData=false, MaterialInstance? materialInstance,
|
||||
PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) async {
|
||||
throw UnimplementedError();
|
||||
// final ThermionEntity jsEntity = await _shim
|
||||
@@ -727,8 +739,9 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setParent(ThermionEntity child, ThermionEntity parent) async {
|
||||
await _shim.setParent(child, parent).toDart;
|
||||
Future<void> setParent(ThermionEntity child, ThermionEntity parent,
|
||||
{bool preserveScaling = false}) async {
|
||||
await _shim.setParent(child, parent, preserveScaling).toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -741,14 +754,6 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
await _shim.setPriority(entityId, priority).toDart;
|
||||
}
|
||||
|
||||
Scene? _scene;
|
||||
|
||||
// @override
|
||||
Scene get scene {
|
||||
_scene ??= SceneImpl(this);
|
||||
return _scene!;
|
||||
}
|
||||
|
||||
AbstractGizmo? get gizmo => null;
|
||||
|
||||
@override
|
||||
@@ -826,4 +831,253 @@ class ThermionViewerJS implements ThermionViewer {
|
||||
void onDispose(Future Function() callback) {
|
||||
_onDispose.add(callback);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setShadowType(ShadowType shadowType) {
|
||||
return _shim.setShadowType(shadowType.index).toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
Future setShadowsEnabled(bool enabled) {
|
||||
return _shim.setShadowsEnabled(enabled).toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) {
|
||||
return _shim.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> capture() async {
|
||||
final captured = await _shim.capture().toDart;
|
||||
return captured.toDart;
|
||||
}
|
||||
|
||||
@override
|
||||
late (double, double) viewportDimensions;
|
||||
|
||||
@override
|
||||
Future<Aabb2> getBoundingBox(ThermionEntity entity) {
|
||||
// return _shim.getBoundingBox(entity);
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getCameraFov(bool horizontal) {
|
||||
// TODO: implement getCameraFov
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity,
|
||||
double viewportX, double viewportY, double x, double y, double z) {
|
||||
// TODO: implement queueRelativePositionUpdateWorldAxis
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
double pixelRatio = 0.0;
|
||||
|
||||
@override
|
||||
Future createIbl(double r, double g, double b, double intensity) {
|
||||
// TODO: implement createIbl
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement gizmoPickResult
|
||||
Stream<FilamentPickResult> get gizmoPickResult => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
void pickGizmo(int x, int y) {
|
||||
// TODO: implement pickGizmo
|
||||
}
|
||||
|
||||
@override
|
||||
Future setGizmoVisibility(bool visible) {
|
||||
// TODO: implement setGizmoVisibility
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLayerEnabled(int layer, bool enabled) {
|
||||
// TODO: implement setLayerEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement entitiesAdded
|
||||
Stream<ThermionEntity> get entitiesAdded => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
// TODO: implement entitiesRemoved
|
||||
Stream<ThermionEntity> get entitiesRemoved => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<ThermionEntity?> getAncestor(ThermionEntity entity) {
|
||||
// TODO: implement getAncestor
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getCameraNear() {
|
||||
// TODO: implement getCameraNear
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity) {
|
||||
// TODO: implement getViewportBoundingBox
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement lightsAdded
|
||||
Stream<ThermionEntity> get lightsAdded => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
// TODO: implement lightsRemoved
|
||||
Stream<ThermionEntity> get lightsRemoved => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int layer=4, int priority =4 }) {
|
||||
// TODO: implement loadGlbFromBuffer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future queuePositionUpdateFromViewportCoords(ThermionEntity entity, double x, double y) {
|
||||
// TODO: implement queuePositionUpdateFromViewportCoords
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future removeStencilHighlight(ThermionEntity entity) {
|
||||
// TODO: implement removeStencilHighlight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setCameraModelMatrix4(Matrix4 matrix) {
|
||||
// TODO: implement setCameraModelMatrix4
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) {
|
||||
// TODO: implement setLightDirection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setLightPosition(ThermionEntity lightEntity, double x, double y, double z) {
|
||||
// TODO: implement setLightPosition
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) {
|
||||
// TODO: implement setMaterialPropertyFloat
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, int materialIndex, double f1, double f2, double f3, double f4) {
|
||||
// TODO: implement setMaterialPropertyFloat4
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) {
|
||||
// TODO: implement setStencilHighlight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> addDirectLight(DirectLight light) {
|
||||
// TODO: implement addDirectLight
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, {int materialIndex = 0, String parameterName = "baseColorMap"}) {
|
||||
// TODO: implement applyTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionTexture> createTexture(Uint8List data) {
|
||||
// TODO: implement createTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance> createUbershaderMaterialInstance({bool doubleSided = false, bool unlit = false, bool hasVertexColors = false, bool hasBaseColorTexture = false, bool hasNormalTexture = false, bool hasOcclusionTexture = false, bool hasEmissiveTexture = false, bool useSpecularGlossiness = false, AlphaMode alphaMode = AlphaMode.OPAQUE, bool enableDiagnostics = false, bool hasMetallicRoughnessTexture = false, int metallicRoughnessUV = 0, int baseColorUV = 0, bool hasClearCoatTexture = false, int clearCoatUV = 0, bool hasClearCoatRoughnessTexture = false, int clearCoatRoughnessUV = 0, bool hasClearCoatNormalTexture = false, int clearCoatNormalUV = 0, bool hasClearCoat = false, bool hasTransmission = false, bool hasTextureTransforms = false, int emissiveUV = 0, int aoUV = 0, int normalUV = 0, bool hasTransmissionTexture = false, int transmissionUV = 0, bool hasSheenColorTexture = false, int sheenColorUV = 0, bool hasSheenRoughnessTexture = false, int sheenRoughnessUV = 0, bool hasVolumeThicknessTexture = false, int volumeThicknessUV = 0, bool hasSheen = false, bool hasIOR = false, bool hasVolume = false}) {
|
||||
// TODO: implement createUbershaderMaterialInstance
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance> createUnlitMaterialInstance() {
|
||||
// TODO: implement createUnlitMaterialInstance
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroyMaterialInstance(covariant MaterialInstance materialInstance) {
|
||||
// TODO: implement destroyMaterialInstance
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroyTexture(covariant ThermionTexture texture) {
|
||||
// TODO: implement destroyTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> getMainCameraEntity() {
|
||||
// TODO: implement getMainCameraEntity
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MaterialInstance?> getMaterialInstanceAt(ThermionEntity entity, int index) {
|
||||
// TODO: implement getMaterialInstanceAt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
void requestFrame() {
|
||||
// TODO: implement requestFrame
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement sceneUpdated
|
||||
Stream<SceneUpdateEvent> get sceneUpdated => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future setLayerVisibility(int layer, bool visible) {
|
||||
// TODO: implement setLayerVisibility
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) {
|
||||
// TODO: implement setMaterialPropertyInt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setVisibilityLayer(ThermionEntity entity, int layer) {
|
||||
// TODO: implement setVisibilityLayer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) {
|
||||
// TODO: implement setCameraLensProjection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,10 @@ import 'dart:js_interop';
|
||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||
|
||||
///
|
||||
/// An extension type on [JSObject] that represents a
|
||||
/// An extension type on [JSObject] that represents a
|
||||
/// Javascript shim implementation of the [ThermionViewer] interface.
|
||||
///
|
||||
///
|
||||
extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
|
||||
@JS('initialized')
|
||||
external JSPromise<JSBoolean> get initialized;
|
||||
|
||||
@@ -23,6 +22,9 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
@JS('render')
|
||||
external JSPromise render();
|
||||
|
||||
@JS('capture')
|
||||
external JSPromise<JSUint8Array> capture();
|
||||
|
||||
@JS('setFrameRate')
|
||||
external JSPromise setFrameRate(int framerate);
|
||||
|
||||
@@ -136,6 +138,9 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
external JSPromise<JSNumber> getAnimationDuration(
|
||||
ThermionEntity entity, int animationIndex);
|
||||
|
||||
@JS('clearMorphAnimationData')
|
||||
external void clearMorphAnimationData(ThermionEntity entity);
|
||||
|
||||
@JS('setMorphAnimationData')
|
||||
external JSPromise setMorphAnimationData(
|
||||
ThermionEntity entity,
|
||||
@@ -182,6 +187,7 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
bool reverse,
|
||||
bool replaceActive,
|
||||
double crossfade,
|
||||
double startOffset,
|
||||
);
|
||||
|
||||
@JS('playAnimationByName')
|
||||
@@ -214,7 +220,7 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
external JSPromise<JSNumber> getMainCamera();
|
||||
|
||||
@JS('setCameraFov')
|
||||
external JSPromise setCameraFov(double degrees, double width, double height);
|
||||
external JSPromise setCameraFov(double degrees, bool horizontal);
|
||||
|
||||
@JS('setToneMapping')
|
||||
external JSPromise setToneMapping(int mapper);
|
||||
@@ -372,7 +378,7 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
JSArray<JSNumber> indices, String? materialPath, int primitiveType);
|
||||
|
||||
@JS('setParent')
|
||||
external JSPromise setParent(ThermionEntity child, ThermionEntity parent);
|
||||
external JSPromise setParent(ThermionEntity child, ThermionEntity parent, bool preserveScaling);
|
||||
|
||||
@JS('getParent')
|
||||
external JSPromise<JSNumber> getParent(ThermionEntity child);
|
||||
@@ -403,7 +409,16 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
||||
ThermionEntity entity, JSArray<JSNumber> transform);
|
||||
|
||||
@JS('setBoneTransform')
|
||||
external JSPromise setBoneTransform(
|
||||
ThermionEntity entity, int boneIndex, JSArray<JSNumber> transform, int skinIndex);
|
||||
}
|
||||
external JSPromise setBoneTransform(ThermionEntity entity, int boneIndex,
|
||||
JSArray<JSNumber> transform, int skinIndex);
|
||||
|
||||
@JS('setShadowsEnabled')
|
||||
external JSPromise setShadowsEnabled(bool enabled);
|
||||
|
||||
@JS('setShadowType')
|
||||
external JSPromise setShadowType(int shadowType);
|
||||
|
||||
@JS('setSoftShadowOptions')
|
||||
external JSPromise setSoftShadowOptions(
|
||||
double penumbraScale, double penumbraRatioScale);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
library;
|
||||
|
||||
export 'src/thermion_viewer_dart_bridge.dart';
|
||||
export 'src/thermion_viewer_js_shim.dart';
|
||||
export 'src/thermion_viewer_js.dart';
|
||||
@@ -0,0 +1,16 @@
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class ThermionWasmCamera extends Camera {
|
||||
|
||||
final int pointer;
|
||||
|
||||
ThermionWasmCamera(this.pointer);
|
||||
|
||||
@override
|
||||
Future setProjectionMatrixWithCulling(
|
||||
Matrix4 projectionMatrix, double near, double far) {
|
||||
// TODO: implement setProjectionMatrixWithCulling
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
import 'package:thermion_dart/thermion_dart/viewer/shared_types/material.dart';
|
||||
|
||||
class ThermionWasmMaterialInstance extends MaterialInstance {
|
||||
final int pointer;
|
||||
|
||||
ThermionWasmMaterialInstance(this.pointer);
|
||||
@override
|
||||
Future setDepthCullingEnabled(bool enabled) {
|
||||
// TODO: implement setDepthCullingEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setDepthWriteEnabled(bool enabled) {
|
||||
// TODO: implement setDepthWriteEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
library;
|
||||
|
||||
export 'src/thermion_viewer_wasm.dart' show ThermionViewerWasm;
|
||||
104
thermion_dart/native/include/APIBoundaryTypes.h
Normal file
104
thermion_dart/native/include/APIBoundaryTypes.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int32_t EntityId;
|
||||
typedef int32_t _ManipulatorMode;
|
||||
typedef struct TCamera TCamera;
|
||||
typedef struct TMaterialInstance TMaterialInstance;
|
||||
typedef struct TEngine TEngine;
|
||||
typedef struct TViewer TViewer;
|
||||
|
||||
struct TMaterialKey {
|
||||
bool doubleSided = 1;
|
||||
bool unlit = 1;
|
||||
bool hasVertexColors = 1;
|
||||
bool hasBaseColorTexture = 1;
|
||||
bool hasNormalTexture = 1;
|
||||
bool hasOcclusionTexture = 1;
|
||||
bool hasEmissiveTexture = 1;
|
||||
bool useSpecularGlossiness = 1;
|
||||
int alphaMode = 4;
|
||||
bool enableDiagnostics = 4;
|
||||
union {
|
||||
#ifdef __cplusplus
|
||||
struct {
|
||||
bool hasMetallicRoughnessTexture;
|
||||
uint8_t metallicRoughnessUV;
|
||||
};
|
||||
struct {
|
||||
bool hasSpecularGlossinessTexture;
|
||||
uint8_t specularGlossinessUV;
|
||||
};
|
||||
#else
|
||||
struct {
|
||||
bool hasMetallicRoughnessTexture = 1;
|
||||
uint8_t metallicRoughnessUV = 7;
|
||||
};
|
||||
struct {
|
||||
bool hasSpecularGlossinessTexture = 1;
|
||||
uint8_t specularGlossinessUV = 7;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
uint8_t baseColorUV;
|
||||
// -- 32 bit boundary --
|
||||
bool hasClearCoatTexture = 1;
|
||||
uint8_t clearCoatUV = 7;
|
||||
bool hasClearCoatRoughnessTexture = 1;
|
||||
uint8_t clearCoatRoughnessUV = 7;
|
||||
bool hasClearCoatNormalTexture = 1;
|
||||
uint8_t clearCoatNormalUV = 7;
|
||||
bool hasClearCoat = 1;
|
||||
bool hasTransmission = 1;
|
||||
bool hasTextureTransforms = 6;
|
||||
// -- 32 bit boundary --
|
||||
uint8_t emissiveUV;
|
||||
uint8_t aoUV;
|
||||
uint8_t normalUV;
|
||||
bool hasTransmissionTexture = 1;
|
||||
uint8_t transmissionUV = 7;
|
||||
// -- 32 bit boundary --
|
||||
bool hasSheenColorTexture = 1;
|
||||
uint8_t sheenColorUV = 7;
|
||||
bool hasSheenRoughnessTexture = 1;
|
||||
uint8_t sheenRoughnessUV = 7;
|
||||
bool hasVolumeThicknessTexture = 1;
|
||||
uint8_t volumeThicknessUV = 7;
|
||||
bool hasSheen = 1;
|
||||
bool hasIOR = 1;
|
||||
bool hasVolume = 1;
|
||||
} ;
|
||||
typedef struct TMaterialKey TMaterialKey;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
double y;
|
||||
double z;
|
||||
double w;
|
||||
} double4;
|
||||
|
||||
typedef struct {
|
||||
double col1[4];
|
||||
double col2[4];
|
||||
double col3[4];
|
||||
double col4[4];
|
||||
} double4x4;
|
||||
|
||||
struct Aabb2 {
|
||||
float minX;
|
||||
float minY;
|
||||
float maxX;
|
||||
float maxY;
|
||||
};
|
||||
|
||||
typedef struct Aabb2 Aabb2;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
59
thermion_dart/native/include/CustomGeometry.hpp
Normal file
59
thermion_dart/native/include/CustomGeometry.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/VertexBuffer.h>
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/Frustum.h>
|
||||
|
||||
namespace thermion_filament
|
||||
{
|
||||
|
||||
using namespace filament;
|
||||
|
||||
// CustomGeometry.h
|
||||
class CustomGeometry {
|
||||
public:
|
||||
CustomGeometry(
|
||||
float* vertices,
|
||||
uint32_t numVertices,
|
||||
float* normals,
|
||||
uint32_t numNormals,
|
||||
float *uvs,
|
||||
uint32_t numUvs,
|
||||
uint16_t* indices,
|
||||
uint32_t numIndices,
|
||||
RenderableManager::PrimitiveType primitiveType,
|
||||
Engine* engine);
|
||||
~CustomGeometry();
|
||||
|
||||
VertexBuffer* vertexBuffer() const;
|
||||
IndexBuffer* indexBuffer() const;
|
||||
Box getBoundingBox() const;
|
||||
|
||||
float* vertices = nullptr;
|
||||
float* normals = nullptr;
|
||||
float *uvs = nullptr;
|
||||
uint32_t numVertices = 0;
|
||||
uint16_t* indices = 0;
|
||||
uint32_t numIndices = 0;
|
||||
Box boundingBox;
|
||||
RenderableManager::PrimitiveType primitiveType;
|
||||
|
||||
private:
|
||||
Engine* _engine;
|
||||
bool _vertexBufferFreed = false;
|
||||
bool _indexBufferFreed = false;
|
||||
|
||||
void computeBoundingBox();
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -42,8 +42,6 @@ namespace thermion_filament
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace gltfio;
|
||||
using namespace camutils;
|
||||
|
||||
@@ -71,12 +69,13 @@ namespace thermion_filament
|
||||
void loadIbl(const char *const iblUri, float intensity);
|
||||
void removeIbl();
|
||||
void rotateIbl(const math::mat3f &matrix);
|
||||
void createIbl(float r, float g, float b, float intensity);
|
||||
|
||||
void removeEntity(EntityId asset);
|
||||
void clearEntities();
|
||||
|
||||
void updateViewportAndCameraProjection(int height, int width, float scaleFactor);
|
||||
void render(
|
||||
void updateViewport(uint32_t width, uint32_t height);
|
||||
bool render(
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
@@ -86,7 +85,10 @@ namespace thermion_filament
|
||||
bool setCamera(EntityId asset, const char *nodeName);
|
||||
void setMainCamera();
|
||||
EntityId getMainCamera();
|
||||
void setCameraFov(double fovDegrees, double aspect);
|
||||
Camera* getCamera(EntityId entity);
|
||||
|
||||
float getCameraFov(bool horizontal);
|
||||
void setCameraFov(double fovDegrees, bool horizontal);
|
||||
|
||||
void createSwapChain(const void *surface, uint32_t width, uint32_t height);
|
||||
void destroySwapChain();
|
||||
@@ -100,24 +102,8 @@ namespace thermion_filament
|
||||
void clearBackgroundImage();
|
||||
void setBackgroundImagePosition(float x, float y, bool clamp);
|
||||
|
||||
// Camera methods
|
||||
void moveCameraToAsset(EntityId entityId);
|
||||
void setViewFrustumCulling(bool enabled);
|
||||
void setCameraExposure(float aperture, float shutterSpeed, float sensitivity);
|
||||
void setCameraPosition(float x, float y, float z);
|
||||
void setCameraRotation(float w, float x, float y, float z);
|
||||
const math::mat4 getCameraModelMatrix();
|
||||
const math::mat4 getCameraViewMatrix();
|
||||
const math::mat4 getCameraProjectionMatrix();
|
||||
const math::mat4 getCameraCullingProjectionMatrix();
|
||||
const filament::Frustum getCameraFrustum();
|
||||
void setCameraModelMatrix(const float *const matrix);
|
||||
void setCameraProjectionMatrix(const double *const matrix, double near, double far);
|
||||
void setCameraFocalLength(float focalLength);
|
||||
void setCameraCulling(double near, double far);
|
||||
double getCameraCullingNear();
|
||||
double getCameraCullingFar();
|
||||
void setCameraFocusDistance(float focusDistance);
|
||||
|
||||
void setCameraManipulatorOptions(filament::camutils::Mode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||
void grabBegin(float x, float y, bool pan);
|
||||
void grabUpdate(float x, float y);
|
||||
@@ -126,6 +112,9 @@ namespace thermion_filament
|
||||
void scrollUpdate(float x, float y, float delta);
|
||||
void scrollEnd();
|
||||
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
||||
Engine* getEngine() {
|
||||
return _engine;
|
||||
}
|
||||
|
||||
EntityId addLight(
|
||||
LightManager::Type t,
|
||||
@@ -144,12 +133,15 @@ namespace thermion_filament
|
||||
float sunHaloSize,
|
||||
float sunHaloFallof,
|
||||
bool shadows);
|
||||
void setLightPosition(EntityId entityId, float x, float y, float z);
|
||||
void setLightDirection(EntityId entityId, float x, float y, float z);
|
||||
void removeLight(EntityId entityId);
|
||||
void clearLights();
|
||||
void setPostProcessing(bool enabled);
|
||||
|
||||
void setRecording(bool recording);
|
||||
void setRecordingOutputDirectory(const char *path);
|
||||
void capture(uint8_t *out, bool useFence, void (*onComplete)());
|
||||
|
||||
void setAntiAliasing(bool msaaEnabled, bool fxaaEnabled, bool taaEnabled);
|
||||
void setDepthOfField();
|
||||
@@ -157,18 +149,20 @@ namespace thermion_filament
|
||||
void setShadowType(ShadowType shadowType);
|
||||
void setSoftShadowOptions( float penumbraScale, float penumbraRatioScale);
|
||||
|
||||
EntityId createGeometry(float *vertices, uint32_t numVertices, uint16_t *indices, uint32_t numIndices, filament::RenderableManager::PrimitiveType primitiveType = RenderableManager::PrimitiveType::TRIANGLES, const char *materialPath = nullptr);
|
||||
|
||||
SceneManager *const getSceneManager()
|
||||
{
|
||||
return (SceneManager *const)_sceneManager;
|
||||
}
|
||||
|
||||
void unprojectTexture(EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight);
|
||||
|
||||
private:
|
||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||
void* _context = nullptr;
|
||||
Scene *_scene = nullptr;
|
||||
|
||||
View *_view = nullptr;
|
||||
|
||||
Engine *_engine = nullptr;
|
||||
thermion_filament::ThreadPool *_tp = nullptr;
|
||||
Renderer *_renderer = nullptr;
|
||||
@@ -187,32 +181,26 @@ namespace thermion_filament
|
||||
Skybox *_skybox = nullptr;
|
||||
Texture *_iblTexture = nullptr;
|
||||
IndirectLight *_indirectLight = nullptr;
|
||||
bool _recomputeAabb = false;
|
||||
bool _actualSize = false;
|
||||
|
||||
float _frameInterval = 1000.0 / 60.0;
|
||||
|
||||
// Camera properties
|
||||
Camera *_mainCamera = nullptr; // the default camera added to every scene. If you want the *active* camera, access via View.
|
||||
float _cameraFocalLength = 28.0f;
|
||||
float _cameraFocusDistance = 0.0f;
|
||||
|
||||
Manipulator<double> *_manipulator = nullptr;
|
||||
filament::camutils::Mode _manipulatorMode = filament::camutils::Mode::ORBIT;
|
||||
double _orbitSpeedX = 0.01;
|
||||
double _orbitSpeedY = 0.01;
|
||||
double _zoomSpeed = 0.01;
|
||||
math::mat4f _cameraPosition;
|
||||
math::mat4f _cameraRotation;
|
||||
|
||||
void _createManipulator();
|
||||
double _near = 0.05;
|
||||
double _far = 1000.0;
|
||||
|
||||
ColorGrading *colorGrading = nullptr;
|
||||
|
||||
// background image properties
|
||||
uint32_t _imageHeight = 0;
|
||||
uint32_t _imageWidth = 0;
|
||||
mat4f _imageScale;
|
||||
filament::math::mat4f _imageScale;
|
||||
Texture *_imageTexture = nullptr;
|
||||
Texture *_dummyImageTexture = nullptr;
|
||||
utils::Entity _imageEntity;
|
||||
|
||||
113
thermion_dart/native/include/Gizmo.hpp
Normal file
113
thermion_dart/native/include/Gizmo.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#include <utils/Entity.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Material.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/View.h>
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/FilamentInstance.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/InstanceBuffer.h>
|
||||
|
||||
#include "material/gizmo.h"
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
|
||||
class Gizmo {
|
||||
|
||||
enum Axis { X, Y, Z};
|
||||
|
||||
class PickCallbackHandler {
|
||||
public:
|
||||
PickCallbackHandler(Gizmo* gizmo, void (*callback)(EntityId entityId, int x, int y)) : _gizmo(gizmo), _callback(callback) {};
|
||||
void handle(filament::View::PickingQueryResult const &result) {
|
||||
auto x = static_cast<int32_t>(result.fragCoords.x);
|
||||
auto y= static_cast<int32_t>(result.fragCoords.y);
|
||||
for(int i = 0; i < 7; i++) {
|
||||
if(_gizmo->_entities[i] == result.renderable) {
|
||||
if(i < 4) {
|
||||
return;
|
||||
}
|
||||
_gizmo->highlight(_gizmo->_entities[i - 4]);
|
||||
_callback(Entity::smuggle(_gizmo->_entities[i - 4]), x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_gizmo->unhighlight();
|
||||
_callback(0, x, y);
|
||||
delete(this);
|
||||
}
|
||||
|
||||
private:
|
||||
Gizmo* _gizmo;
|
||||
void (*_callback)(EntityId entityId, int x, int y);
|
||||
|
||||
};
|
||||
|
||||
public:
|
||||
Gizmo(Engine& engine, View *view, Scene *scene);
|
||||
~Gizmo();
|
||||
|
||||
Entity x() {
|
||||
return _entities[0];
|
||||
};
|
||||
Entity y() {
|
||||
return _entities[1];
|
||||
};
|
||||
Entity z() {
|
||||
return _entities[2];
|
||||
};
|
||||
Entity center() {
|
||||
return _entities[3];
|
||||
};
|
||||
View* view() {
|
||||
return _view;
|
||||
}
|
||||
|
||||
bool isActive() {
|
||||
return _isActive;
|
||||
}
|
||||
|
||||
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
||||
bool isGizmoEntity(Entity entity);
|
||||
void setVisibility(bool visible);
|
||||
|
||||
private:
|
||||
void createTransparentRectangles();
|
||||
void highlight(Entity entity);
|
||||
void unhighlight();
|
||||
Engine &_engine;
|
||||
View *_view;
|
||||
Scene *_scene;
|
||||
filament::Camera *_camera;
|
||||
utils::Entity _entities[7] = { utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity() };
|
||||
Material* _material;
|
||||
MaterialInstance* _materialInstances[7];
|
||||
math::float4 inactiveColors[3] {
|
||||
math::float4 { 1.0f, 0.0f, 0.0f, 0.5f },
|
||||
math::float4 { 0.0f, 1.0f, 0.0f, 0.5f },
|
||||
math::float4 { 0.0f, 0.0f, 1.0f, 0.5f },
|
||||
};
|
||||
math::float4 activeColors[3] {
|
||||
math::float4 { 1.0f, 0.0f, 0.0f, 1.0f },
|
||||
math::float4 { 0.0f, 1.0f, 0.0f, 1.0f },
|
||||
math::float4 { 0.0f, 0.0f, 1.0f, 1.0f },
|
||||
};
|
||||
bool _isActive = true;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
52
thermion_dart/native/include/GridOverlay.hpp
Normal file
52
thermion_dart/native/include/GridOverlay.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <utils/Entity.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Material.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/View.h>
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/FilamentInstance.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/InstanceBuffer.h>
|
||||
|
||||
#include "material/gizmo.h"
|
||||
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
|
||||
class GridOverlay {
|
||||
public:
|
||||
GridOverlay(Engine& engine);
|
||||
void destroy();
|
||||
|
||||
utils::Entity sphere() {
|
||||
return _sphereEntity;
|
||||
}
|
||||
|
||||
utils::Entity grid() {
|
||||
return _gridEntity;
|
||||
}
|
||||
|
||||
private:
|
||||
Engine &_engine;
|
||||
utils::Entity _gridEntity;
|
||||
utils::Entity _sphereEntity;
|
||||
Material* _material;
|
||||
MaterialInstance* _materialInstance;
|
||||
MaterialInstance* _sphereMaterialInstance;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -4,8 +4,11 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
@@ -14,15 +17,21 @@
|
||||
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/InstanceBuffer.h>
|
||||
#include <utils/NameComponentManager.h>
|
||||
|
||||
#include "material/gizmo.h"
|
||||
#include "utils/NameComponentManager.h"
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "Gizmo.hpp"
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "GridOverlay.hpp"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "components/CollisionComponentManager.hpp"
|
||||
#include "components/AnimationComponentManager.hpp"
|
||||
|
||||
#include "tsl/robin_map.h"
|
||||
|
||||
|
||||
namespace thermion_filament
|
||||
{
|
||||
typedef int32_t EntityId;
|
||||
@@ -37,13 +46,45 @@ namespace thermion_filament
|
||||
class SceneManager
|
||||
{
|
||||
public:
|
||||
SceneManager(const ResourceLoaderWrapperImpl *const loader,
|
||||
SceneManager(View* view,
|
||||
const ResourceLoaderWrapperImpl *const loader,
|
||||
Engine *engine,
|
||||
Scene *scene,
|
||||
const char *uberArchivePath);
|
||||
~SceneManager();
|
||||
|
||||
EntityId loadGltf(const char *uri, const char *relativeResourcePath);
|
||||
enum LAYERS {
|
||||
DEFAULT_ASSETS = 0,
|
||||
BACKGROUND = 6,
|
||||
OVERLAY = 7,
|
||||
};
|
||||
|
||||
class HighlightOverlay {
|
||||
public:
|
||||
HighlightOverlay(EntityId id, SceneManager* const sceneManager, Engine* const engine, float r, float g, float b);
|
||||
~HighlightOverlay();
|
||||
|
||||
bool isValid() {
|
||||
return !_entity.isNull();
|
||||
}
|
||||
|
||||
private:
|
||||
MaterialInstance* _highlightMaterialInstance = nullptr;
|
||||
bool _isGeometryEntity = false;
|
||||
bool _isGltfAsset = false;
|
||||
FilamentInstance* _newInstance = nullptr;
|
||||
Entity _entity;
|
||||
Engine* const _engine;
|
||||
SceneManager* const _sceneManager;
|
||||
};
|
||||
|
||||
////
|
||||
/// @brief Load the glTF file from the specified path and adds all entities to the scene.
|
||||
/// @param uri the path to the asset. Should be either asset:// (representing a Flutter asset), or file:// (representing a filesystem file).
|
||||
/// @param relativeResourcePath the (relative) path to the asset's resources.
|
||||
/// @return the glTF entity.
|
||||
///
|
||||
EntityId loadGltf(const char *uri, const char *relativeResourcePath, bool keepData = false);
|
||||
|
||||
////
|
||||
/// @brief Load the GLB from the specified path, optionally creating multiple instances.
|
||||
@@ -51,8 +92,8 @@ namespace thermion_filament
|
||||
/// @param numInstances the number of instances to create.
|
||||
/// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset.
|
||||
///
|
||||
EntityId loadGlb(const char *uri, int numInstances);
|
||||
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1);
|
||||
EntityId loadGlb(const char *uri, int numInstances, bool keepData);
|
||||
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0);
|
||||
EntityId createInstance(EntityId entityId);
|
||||
|
||||
void remove(EntityId entity);
|
||||
@@ -69,6 +110,8 @@ namespace thermion_filament
|
||||
void setRotation(EntityId e, float rads, float x, float y, float z, float w);
|
||||
void queuePositionUpdate(EntityId e, float x, float y, float z, bool relative);
|
||||
void queueRotationUpdate(EntityId e, float rads, float x, float y, float z, float w, bool relative);
|
||||
void queueRelativePositionUpdateWorldAxis(EntityId entity, float viewportCoordX, float viewportCoordY, float x, float y, float z);
|
||||
void queueRelativePositionUpdateFromViewportVector(EntityId entityId, float viewportCoordX, float viewportCoordY);
|
||||
const utils::Entity *getCameraEntities(EntityId e);
|
||||
size_t getCameraEntityCount(EntityId e);
|
||||
const utils::Entity *getLightEntities(EntityId e) noexcept;
|
||||
@@ -87,6 +130,9 @@ namespace thermion_filament
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
void clearMorphAnimationBuffer(
|
||||
EntityId entityId);
|
||||
|
||||
bool setMorphTargetWeights(EntityId entityId, const float *const weights, int count);
|
||||
|
||||
math::mat4f getLocalTransform(EntityId entityId);
|
||||
@@ -126,10 +172,14 @@ namespace thermion_filament
|
||||
void resetBones(EntityId entityId);
|
||||
bool setTransform(EntityId entityId, math::mat4f transform);
|
||||
bool updateBoneMatrices(EntityId entityId);
|
||||
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f);
|
||||
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f, float startOffset = 0.0f);
|
||||
void stopAnimation(EntityId e, int index);
|
||||
void setMorphTargetWeights(const char *const entityName, float *weights, int count);
|
||||
void loadTexture(EntityId entity, const char *resourcePath, int renderableIndex);
|
||||
|
||||
Texture* createTexture(const uint8_t* data, size_t length, const char* name);
|
||||
bool applyTexture(EntityId entityId, Texture *texture, const char* slotName, int materialIndex);
|
||||
void destroyTexture(Texture* texture);
|
||||
|
||||
void setAnimationFrame(EntityId entity, int animationIndex, int animationFrame);
|
||||
bool hide(EntityId entity, const char *meshName);
|
||||
bool reveal(EntityId entity, const char *meshName);
|
||||
@@ -143,10 +193,21 @@ namespace thermion_filament
|
||||
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
||||
void removeCollisionComponent(EntityId entityId);
|
||||
EntityId getParent(EntityId child);
|
||||
void setParent(EntityId child, EntityId parent);
|
||||
EntityId getAncestor(EntityId child);
|
||||
void setParent(EntityId child, EntityId parent, bool preserveScaling);
|
||||
bool addAnimationComponent(EntityId entity);
|
||||
void removeAnimationComponent(EntityId entity);
|
||||
|
||||
/// @brief renders an outline around the specified entity.
|
||||
///
|
||||
///
|
||||
void setStencilHighlight(EntityId entity, float r, float g, float b);
|
||||
|
||||
/// @brief removes the outline around the specified entity.
|
||||
///
|
||||
///
|
||||
void removeStencilHighlight(EntityId entity);
|
||||
|
||||
/// @brief returns the number of instances of the FilamentAsset represented by the given entity.
|
||||
/// @param entityId
|
||||
/// @return the number of instances
|
||||
@@ -161,24 +222,97 @@ namespace thermion_filament
|
||||
///
|
||||
void setPriority(EntityId entity, int priority);
|
||||
|
||||
/// @brief returns the gizmo entity, used to manipulate the global transform for entities
|
||||
/// @param out a pointer to an array of three EntityId {x, y, z}
|
||||
/// @brief returns the 2D min/max viewport coordinates of the bounding box for the specified enitty;
|
||||
/// @param out a pointer large enough to store four floats (the min/max coordinates of the bounding box)
|
||||
/// @return
|
||||
///
|
||||
void getGizmo(EntityId *out);
|
||||
Aabb2 getBoundingBox(EntityId entity);
|
||||
|
||||
///
|
||||
/// Toggles the visibility of the given layer.
|
||||
///
|
||||
void setLayerVisibility(SceneManager::LAYERS layer, bool enabled);
|
||||
|
||||
///
|
||||
/// Creates an entity with the specified geometry/material/normals and adds to the scene.
|
||||
/// If [keepData] is true, stores
|
||||
///
|
||||
EntityId createGeometry(
|
||||
float *vertices,
|
||||
uint32_t numVertices,
|
||||
float *normals,
|
||||
uint32_t numNormals,
|
||||
float *uvs,
|
||||
uint32_t numUvs,
|
||||
uint16_t *indices,
|
||||
uint32_t numIndices,
|
||||
filament::RenderableManager::PrimitiveType primitiveType = RenderableManager::PrimitiveType::TRIANGLES,
|
||||
MaterialInstance* materialInstance = nullptr,
|
||||
bool keepData = false
|
||||
);
|
||||
|
||||
friend class FilamentViewer;
|
||||
|
||||
Gizmo* gizmo = nullptr;
|
||||
|
||||
gltfio::MaterialProvider * const unlitMaterialProvider() {
|
||||
return _unlitMaterialProvider;
|
||||
}
|
||||
|
||||
bool isGeometryEntity(EntityId entity) {
|
||||
return _geometry.find(entity) != _geometry.end();
|
||||
}
|
||||
|
||||
const CustomGeometry* const getGeometry(EntityId entityId) {
|
||||
return _geometry[entityId].get();
|
||||
}
|
||||
|
||||
Scene* const getScene() {
|
||||
return _scene;
|
||||
}
|
||||
|
||||
bool isGltfAsset(EntityId entity) {
|
||||
return getAssetByEntityId(entity) != nullptr;
|
||||
}
|
||||
|
||||
gltfio::FilamentInstance *getInstanceByEntityId(EntityId entityId);
|
||||
gltfio::FilamentAsset *getAssetByEntityId(EntityId entityId);
|
||||
|
||||
gltfio::FilamentInstance *createGltfAssetInstance(FilamentAsset* asset) {
|
||||
return _assetLoader->createInstance(asset);
|
||||
}
|
||||
|
||||
MaterialInstance* getMaterialInstanceAt(EntityId entityId, int materialIndex);
|
||||
|
||||
void setMaterialProperty(EntityId entity, int materialIndex, const char* property, float value);
|
||||
void setMaterialProperty(EntityId entity, int materialIndex, const char* property, int32_t value);
|
||||
void setMaterialProperty(EntityId entityId, int materialIndex, const char* property, filament::math::float4& value);
|
||||
|
||||
MaterialInstance* createUbershaderMaterialInstance(MaterialKey key);
|
||||
void destroy(MaterialInstance* materialInstance);
|
||||
|
||||
gltfio::MaterialProvider* getUbershaderProvider() {
|
||||
return _ubershaderProvider;
|
||||
}
|
||||
|
||||
MaterialInstance* createUnlitMaterialInstance();
|
||||
|
||||
void setVisibilityLayer(EntityId entityId, int layer);
|
||||
|
||||
private:
|
||||
gltfio::AssetLoader *_assetLoader = nullptr;
|
||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||
Engine *_engine;
|
||||
Scene *_scene;
|
||||
Engine *_engine = nullptr;
|
||||
Scene *_scene = nullptr;
|
||||
View* _view = nullptr;
|
||||
|
||||
gltfio::MaterialProvider *_ubershaderProvider = nullptr;
|
||||
gltfio::MaterialProvider *_unlitMaterialProvider = nullptr;
|
||||
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
|
||||
gltfio::TextureProvider *_stbDecoder = nullptr;
|
||||
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
||||
std::mutex _mutex;
|
||||
std::mutex _stencilMutex;
|
||||
|
||||
utils::NameComponentManager *_ncm;
|
||||
|
||||
@@ -187,22 +321,20 @@ namespace thermion_filament
|
||||
gltfio::FilamentInstance *>
|
||||
_instances;
|
||||
tsl::robin_map<EntityId, gltfio::FilamentAsset *> _assets;
|
||||
tsl::robin_map<EntityId, unique_ptr<CustomGeometry>> _geometry;
|
||||
tsl::robin_map<EntityId, unique_ptr<HighlightOverlay>> _highlighted;
|
||||
tsl::robin_map<EntityId, std::tuple<math::float3, bool, math::quatf, bool, float>> _transformUpdates;
|
||||
std::set<Texture*> _textures;
|
||||
|
||||
AnimationComponentManager *_animationComponentManager = nullptr;
|
||||
CollisionComponentManager *_collisionComponentManager = nullptr;
|
||||
|
||||
gltfio::FilamentInstance *getInstanceByEntityId(EntityId entityId);
|
||||
gltfio::FilamentAsset *getAssetByEntityId(EntityId entityId);
|
||||
|
||||
utils::Entity findEntityByName(
|
||||
const gltfio::FilamentInstance *instance,
|
||||
const char *entityName);
|
||||
|
||||
EntityId addGizmo();
|
||||
utils::Entity _gizmo[3];
|
||||
Material* _gizmoMaterial;
|
||||
MaterialInstance* _gizmoMaterialInstances[3];
|
||||
GridOverlay* _gridOverlay = nullptr;
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,77 +46,87 @@
|
||||
#include <stddef.h>
|
||||
#endif
|
||||
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
|
||||
typedef int32_t EntityId;
|
||||
typedef int32_t _ManipulatorMode;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const void *create_filament_viewer(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void *get_scene_manager(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target(const void *const viewer, intptr_t texture, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(const void *const viewer, const char *path, bool fillHeight);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(const void *const viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(const void *const viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(const void *const viewer, int toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom(const void *const viewer, float strength);
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox(const void *const viewer, const char *skyboxPath);
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl(const void *const viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(const void *const viewer, float *rotationMatrix);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_ibl(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *create_filament_viewer(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void *get_scene_manager(TViewer *viewer);
|
||||
|
||||
// Engine
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(TViewer *viewer, int toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom(TViewer *viewer, float strength);
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath);
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl(TViewer *viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId add_light(
|
||||
const void *const viewer,
|
||||
uint8_t type,
|
||||
float colour,
|
||||
float intensity,
|
||||
float posX,
|
||||
float posY,
|
||||
float posZ,
|
||||
float dirX,
|
||||
float dirY,
|
||||
float dirZ,
|
||||
TViewer *viewer,
|
||||
uint8_t type,
|
||||
float colour,
|
||||
float intensity,
|
||||
float posX,
|
||||
float posY,
|
||||
float posZ,
|
||||
float dirX,
|
||||
float dirY,
|
||||
float dirZ,
|
||||
float falloffRadius,
|
||||
float spotLightConeInner,
|
||||
float spotLightConeOuter,
|
||||
float spotLightConeInner,
|
||||
float spotLightConeOuter,
|
||||
float sunAngularRadius,
|
||||
float sunHaloSize,
|
||||
float sunHaloFallof,
|
||||
bool shadows);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_light(const void *const viewer, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_lights(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, EntityId light, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, EntityId light, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances, bool keepData);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length, bool keepData, int priority, int layer);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath, bool keepData);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId create_instance(void *sceneManager, EntityId id);
|
||||
EMSCRIPTEN_KEEPALIVE int get_instance_count(void *sceneManager, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void get_instances(void *sceneManager, EntityId entityId, EntityId *out);
|
||||
EMSCRIPTEN_KEEPALIVE void set_main_camera(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_camera(const void *const viewer, EntityId entity, const char *nodeName);
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(const void *const viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void render(
|
||||
const void *const viewer,
|
||||
EMSCRIPTEN_KEEPALIVE void set_main_camera(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_camera(TViewer *viewer, EntityId entity, const char *nodeName);
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE bool render(
|
||||
TViewer *viewer,
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data);
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(const void *const viewer, const void *const window, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(const void *const viewer, float interval);
|
||||
EMSCRIPTEN_KEEPALIVE void update_viewport_and_camera_projection(const void *const viewer, uint32_t width, uint32_t height, float scaleFactor);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_begin(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_update(const void *const viewer, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_end(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_begin(const void *const viewer, float x, float y, bool pan);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_update(const void *const viewer, float x, float y);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_end(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void capture(
|
||||
TViewer *viewer,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void));
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(TViewer *viewer, const void *const window, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(TViewer *viewer, float interval);
|
||||
EMSCRIPTEN_KEEPALIVE void update_viewport(TViewer *viewer, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_begin(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_update(TViewer *viewer, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_end(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_begin(TViewer *viewer, float x, float y, bool pan);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_update(TViewer *viewer, float x, float y);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_end(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights(
|
||||
void *sceneManager,
|
||||
EntityId entity,
|
||||
@@ -136,6 +146,14 @@ extern "C"
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(void *const sceneManager, TMaterialKey materialConfig);
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_unlit_material_instance(void *const sceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_material_instance(void *const sceneManager, TMaterialInstance *instance);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(
|
||||
void *sceneManager,
|
||||
EntityId entity);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose(
|
||||
void *sceneManager,
|
||||
@@ -152,82 +170,86 @@ extern "C"
|
||||
float fadeInInSecs,
|
||||
float maxDelta);
|
||||
EMSCRIPTEN_KEEPALIVE void get_local_transform(void *sceneManager,
|
||||
EntityId entityId, float* const);
|
||||
EntityId entityId, float *const);
|
||||
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(void *sceneManager,
|
||||
EntityId entityId, int skinIndex, float* const out, int numBones);
|
||||
EntityId entityId, int skinIndex, float *const out, int numBones);
|
||||
EMSCRIPTEN_KEEPALIVE void get_world_transform(void *sceneManager,
|
||||
EntityId entityId, float* const);
|
||||
EntityId entityId, float *const);
|
||||
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(void *sceneManager,
|
||||
EntityId entityId, int skinIndex, int boneIndex, float* const);
|
||||
EntityId entityId, int skinIndex, int boneIndex, float *const);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_bone_transform(
|
||||
void *sceneManager,
|
||||
EntityId entity,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const transform);
|
||||
EMSCRIPTEN_KEEPALIVE void play_animation(void *sceneManager, EntityId entity, int index, bool loop, bool reverse, bool replaceActive, float crossfade);
|
||||
EMSCRIPTEN_KEEPALIVE void play_animation(void *sceneManager, EntityId entity, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset);
|
||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame(void *sceneManager, EntityId entity, int animationIndex, int animationFrame);
|
||||
EMSCRIPTEN_KEEPALIVE void stop_animation(void *sceneManager, EntityId entity, int index);
|
||||
EMSCRIPTEN_KEEPALIVE int get_animation_count(void *sceneManager, EntityId asset);
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_name(void *sceneManager, EntityId entity, char *const outPtr, int index);
|
||||
EMSCRIPTEN_KEEPALIVE float get_animation_duration(void *sceneManager, EntityId entity, int index);
|
||||
EMSCRIPTEN_KEEPALIVE int get_bone_count(void *sceneManager, EntityId assetEntity, int skinIndex);
|
||||
EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char** outPtr, int skinIndex);
|
||||
EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char **outPtr, int skinIndex);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_bone(void *sceneManager,
|
||||
EntityId entityId,
|
||||
int skinIndex,
|
||||
int boneIndex);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_transform(void* sceneManager, EntityId entityId, const float* const transform);
|
||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(void* sceneManager, EntityId entityId);
|
||||
EntityId entityId,
|
||||
int skinIndex,
|
||||
int boneIndex);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_transform(void *sceneManager, EntityId entityId, const float *const transform);
|
||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(void *sceneManager, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(void *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index);
|
||||
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(void *sceneManager, EntityId assetEntity, EntityId childEntity);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity(const void *const viewer, EntityId asset);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity(TViewer *viewer, EntityId asset);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_material_color(void *sceneManager, EntityId entity, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(void *sceneManager, EntityId asset);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update(void *sceneManager, EntityId entity, float x, float y, float z, bool relative);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(void *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(void *sceneManager, EntityId entity, float viewportX, float viewportY);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_rotation_update(void *sceneManager, EntityId entity, float rads, float x, float y, float z, float w, bool relative);
|
||||
EMSCRIPTEN_KEEPALIVE void set_position(void *sceneManager, EntityId entity, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void set_rotation(void *sceneManager, EntityId entity, float rads, float x, float y, float z, float w);
|
||||
EMSCRIPTEN_KEEPALIVE void set_scale(void *sceneManager, EntityId entity, float scale);
|
||||
|
||||
// Camera methods
|
||||
EMSCRIPTEN_KEEPALIVE void move_camera_to_asset(const void *const viewer, EntityId asset);
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(const void *const viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(const void *const viewer, float aperture, float shutterSpeed, float sensitivity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_position(const void *const viewer, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void get_camera_position(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_rotation(const void *const viewer, float w, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(const void *const viewer, const float *const matrix);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_model_matrix(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_view_matrix(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_projection_matrix(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(const void *const viewer, const double *const matrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_culling(const void *const viewer, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_near(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_culling_projection_matrix(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(const void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_fov(const void *const viewer, float fovInDegrees, float aspect);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focal_length(const void *const viewer, float focalLength);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(const void *const viewer, float focusDistance);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera);
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_lens_projection(TCamera *camera, double near, double far, double aspect, double focalLength);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float focusDistance);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(TViewer *viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* camera, double4x4 projectionMatrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera_component(TEngine *engine, EntityId entity);
|
||||
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int hide_mesh(void *sceneManager, EntityId entity, const char *meshName);
|
||||
EMSCRIPTEN_KEEPALIVE int reveal_mesh(void *sceneManager, EntityId entity, const char *meshName);
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(void *const viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(void *const viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadow_type(void *const viewer, int shadowType);
|
||||
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(void *const viewer, float penumbraScale, float penumbraRatioScale);
|
||||
EMSCRIPTEN_KEEPALIVE void set_antialiasing(void *const viewer, bool msaa, bool fxaa, bool taa);
|
||||
EMSCRIPTEN_KEEPALIVE void filament_pick(void *const viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadow_type(TViewer *viewer, int shadowType);
|
||||
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(TViewer *viewer, float penumbraScale, float penumbraRatioScale);
|
||||
EMSCRIPTEN_KEEPALIVE void set_antialiasing(TViewer *viewer, bool msaa, bool fxaa, bool taa);
|
||||
EMSCRIPTEN_KEEPALIVE void filament_pick(TViewer *viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(void *const sceneManager, const EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char *name);
|
||||
EMSCRIPTEN_KEEPALIVE int get_entity_count(void *const sceneManager, const EntityId target, bool renderableOnly);
|
||||
EMSCRIPTEN_KEEPALIVE void get_entities(void *const sceneManager, const EntityId target, bool renderableOnly, EntityId *out);
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly);
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording(void *const viewer, bool recording);
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(void *const viewer, const char *outputDirectory);
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording(TViewer *viewer, bool recording);
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(TViewer *viewer, const char *outputDirectory);
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy();
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
|
||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(void *const sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
||||
@@ -235,12 +257,47 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE bool add_animation_component(void *const sceneManager, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_animation_component(void *const sceneManager, EntityId entityId);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId create_geometry(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId create_geometry(
|
||||
void *const sceneManager,
|
||||
float *vertices,
|
||||
int numVertices,
|
||||
float *normals,
|
||||
int numNormals,
|
||||
float *uvs,
|
||||
int numUvs,
|
||||
uint16_t *indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
TMaterialInstance *materialInstance,
|
||||
bool keepData);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_parent(void *const sceneManager, EntityId child);
|
||||
EMSCRIPTEN_KEEPALIVE void set_parent(void *const sceneManager, EntityId child, EntityId parent);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_ancestor(void *const sceneManager, EntityId child);
|
||||
EMSCRIPTEN_KEEPALIVE void set_parent(void *const sceneManager, EntityId child, EntityId parent, bool preserveScaling);
|
||||
EMSCRIPTEN_KEEPALIVE void test_collisions(void *const sceneManager, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_priority(void *const sceneManager, EntityId entityId, int priority);
|
||||
EMSCRIPTEN_KEEPALIVE void get_gizmo(void *const sceneManager, EntityId *out);
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(void *const sceneManager, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(void *const sceneManager, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
|
||||
EMSCRIPTEN_KEEPALIVE void set_layer_visibility(void *const sceneManager, int layer, bool visible);
|
||||
EMSCRIPTEN_KEEPALIVE void set_visibility_layer(void *const sceneManager, EntityId entity, int layer);
|
||||
EMSCRIPTEN_KEEPALIVE void pick_gizmo(void *const sceneManager, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||
EMSCRIPTEN_KEEPALIVE void set_gizmo_visibility(void *const sceneManager, bool visible);
|
||||
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(void *const sceneManager, EntityId entity, float r, float g, float b);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(void *const sceneManager, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_float(void *const sceneManager, EntityId entity, int materialIndex, const char *property, float value);
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_int(void *const sceneManager, EntityId entity, int materialIndex, const char *property, int value);
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(void *const sceneManager, EntityId entity, int materialIndex, const char *property, double4 value);
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_depth_write(void *const sceneManager, EntityId entity, int materialIndex, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer* viewer, EntityId entity,uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight);
|
||||
EMSCRIPTEN_KEEPALIVE void *const create_texture(void *const sceneManager, uint8_t *data, size_t length);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_texture(void *const sceneManager, void *const texture);
|
||||
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(void *const sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance* get_material_instance_at(void *const sceneManager, EntityId entity, int materialIndex);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* materialInstance, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
#ifndef _DART_FILAMENT_FFI_API_H
|
||||
#define _DART_FILAMENT_FFI_API_H
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
///
|
||||
/// This header replicates most of the methods in ThermionDartApi.h.
|
||||
/// It represents the interface for:
|
||||
/// - invoking those methods that must be called on the main Filament engine thread
|
||||
/// - setting up a render loop
|
||||
///
|
||||
typedef int32_t EntityId;
|
||||
typedef void (*FilamentRenderCallback)(void *const owner);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_ffi(
|
||||
void *const context,
|
||||
void *const platform,
|
||||
const char *uberArchivePath,
|
||||
const void *const loader,
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
void *const renderCallbackOwner,
|
||||
void (*callback)(void *const viewer));
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_ffi(void *const viewer, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target_ffi(void *const viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void render_ffi(void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
||||
EMSCRIPTEN_KEEPALIVE void set_rendering_ffi(void *const viewer, bool rendering, void(*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval_ffi(void *const viewer, float frameInterval);
|
||||
EMSCRIPTEN_KEEPALIVE void update_viewport_and_camera_projection_ffi(void *const viewer, const uint32_t width, const uint32_t height, const float scaleFactor, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color_ffi(void *const viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image_ffi(void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_ffi(void *const viewer, const char *path, bool fillHeight, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_ffi(void *const viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_ffi(void *const viewer, int toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom_ffi(void *const viewer, float strength);
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox_ffi(void *const viewer, const char *skyboxPath, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl_ffi(void *const viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_ffi(void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_ibl_ffi(void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void add_light_ffi(
|
||||
void *const viewer,
|
||||
uint8_t type,
|
||||
float colour,
|
||||
float intensity,
|
||||
float posX,
|
||||
float posY,
|
||||
float posZ,
|
||||
float dirX,
|
||||
float dirY,
|
||||
float dirZ,
|
||||
float falloffRadius,
|
||||
float spotLightConeInner,
|
||||
float spotLightConeOuter,
|
||||
float sunAngularRadius,
|
||||
float sunHaloSize,
|
||||
float sunHaloFallof,
|
||||
bool shadows,
|
||||
void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void remove_light_ffi(void *const viewer, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_lights_ffi(void *const viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_ffi(void *const sceneManager, const char *assetPath, int numInstances, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_ffi(void *const sceneManager, const void *const data, size_t length, int numInstances, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_gltf_ffi(void *const sceneManager, const char *assetPath, const char *relativePath, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void create_instance_ffi(void *const sceneManager, EntityId entityId, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity_ffi(void *const viewer, EntityId asset, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities_ffi(void *const viewer, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_ffi(void *const viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights_ffi(
|
||||
void *const sceneManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
float *const weights,
|
||||
int count);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void play_animation_ffi(void *const sceneManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade);
|
||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame_ffi(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame);
|
||||
EMSCRIPTEN_KEEPALIVE void stop_animation_ffi(void *const sceneManager, EntityId asset, int index);
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_count_ffi(void *const sceneManager, EntityId asset, void (*callback)(int));
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_name_ffi(void *const sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_ffi(void *const sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_ffi(void *const sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
|
||||
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_ffi(void *const sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
int numWeights,
|
||||
void (*callback)(bool));
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_ffi(void *sceneManager,
|
||||
EntityId asset, void(*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void set_bone_transform_ffi(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const transform,
|
||||
void (*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing_ffi(void *const viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_ffi(void *const sceneManager, EntityId entityId, void(*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void create_geometry_ffi(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath, void (*callback)(EntityId));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DART_FILAMENT_FFI_API_H
|
||||
126
thermion_dart/native/include/ThermionDartRenderThreadApi.h
Normal file
126
thermion_dart/native/include/ThermionDartRenderThreadApi.h
Normal file
@@ -0,0 +1,126 @@
|
||||
#ifndef _DART_FILAMENT_FFI_API_H
|
||||
#define _DART_FILAMENT_FFI_API_H
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
///
|
||||
/// This header replicates most of the methods in ThermionDartApi.h.
|
||||
/// It represents the interface for:
|
||||
/// - invoking those methods that must be called on the main Filament engine thread
|
||||
/// - setting up a render loop
|
||||
///
|
||||
typedef int32_t EntityId;
|
||||
typedef void (*FilamentRenderCallback)(void *const owner);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_render_thread(
|
||||
void *const context,
|
||||
void *const platform,
|
||||
const char *uberArchivePath,
|
||||
const void *const loader,
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
void *const renderCallbackOwner,
|
||||
void (*callback)(TViewer *viewer));
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(TViewer *viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(TViewer *viewer, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(TViewer *viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void render_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void capture_render_thread(TViewer *viewer, uint8_t* out, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
||||
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void(*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(TViewer *viewer, int toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(TViewer *viewer, float strength);
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl_render_thread(TViewer *viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_ibl_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void add_light_render_thread(
|
||||
TViewer *viewer,
|
||||
uint8_t type,
|
||||
float colour,
|
||||
float intensity,
|
||||
float posX,
|
||||
float posY,
|
||||
float posZ,
|
||||
float dirX,
|
||||
float dirY,
|
||||
float dirZ,
|
||||
float falloffRadius,
|
||||
float spotLightConeInner,
|
||||
float spotLightConeOuter,
|
||||
float sunAngularRadius,
|
||||
float sunHaloSize,
|
||||
float sunHaloFallof,
|
||||
bool shadows,
|
||||
void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void remove_light_render_thread(TViewer *viewer, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_lights_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(void *const sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(void *const sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(void *const sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void create_instance_render_thread(void *const sceneManager, EntityId entityId, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer, EntityId asset, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(TViewer *viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights_render_thread(
|
||||
void *const sceneManager,
|
||||
EntityId asset,
|
||||
const char *const entityName,
|
||||
float *const weights,
|
||||
int count);
|
||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame);
|
||||
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(void *const sceneManager, EntityId asset, int index);
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(void *const sceneManager, EntityId asset, void (*callback)(int));
|
||||
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(void *const sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_render_thread(void *const sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_render_thread(void *const sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
|
||||
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(void *const sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
int numWeights,
|
||||
void (*callback)(bool));
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(void *sceneManager,
|
||||
EntityId asset, void(*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
|
||||
void *sceneManager,
|
||||
EntityId asset,
|
||||
int skinIndex,
|
||||
int boneIndex,
|
||||
const float *const transform,
|
||||
void (*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(void *const sceneManager, EntityId entityId, void(*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
|
||||
void *const sceneManager,
|
||||
float *vertices,
|
||||
int numVertices,
|
||||
float *normals,
|
||||
int numNormals,
|
||||
float *uvs,
|
||||
int numUvs,
|
||||
uint16_t *indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
TMaterialInstance *materialInstance,
|
||||
bool keepData,
|
||||
void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)());
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DART_FILAMENT_FFI_API_H
|
||||
39
thermion_dart/native/include/UnprojectTexture.hpp
Normal file
39
thermion_dart/native/include/UnprojectTexture.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/VertexBuffer.h>
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec2.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <utils/EntityManager.h>
|
||||
#include <backend/PixelBufferDescriptor.h>
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
class UnprojectTexture {
|
||||
public:
|
||||
UnprojectTexture(const CustomGeometry * geometry, Camera& camera, Engine* engine)
|
||||
: _geometry(geometry), _camera(camera), _engine(engine) {}
|
||||
|
||||
void unproject(utils::Entity entity, const uint8_t* inputTexture, uint8_t* outputTexture, uint32_t inputWidth, uint32_t inputHeight,
|
||||
uint32_t outputWidth, uint32_t outputHeight);
|
||||
|
||||
private:
|
||||
const CustomGeometry * _geometry;
|
||||
const Camera& _camera;
|
||||
Engine* _engine;
|
||||
|
||||
math::float3 doUnproject(const math::float2& screenPos, float depth, const math::mat4& invViewProj);
|
||||
bool isInsideTriangle(const math::float2& p, const math::float2& a, const math::float2& b, const math::float2& c);
|
||||
math::float3 barycentric(const math::float2& p, const math::float2& a, const math::float2& b, const math::float2& c);
|
||||
};
|
||||
}
|
||||
@@ -43,6 +43,7 @@ namespace thermion_filament
|
||||
struct AnimationStatus
|
||||
{
|
||||
time_point_t start = time_point_t::max();
|
||||
float startOffset;
|
||||
bool loop = false;
|
||||
bool reverse = false;
|
||||
float durationInSecs = 0;
|
||||
@@ -182,7 +183,7 @@ namespace thermion_filament
|
||||
|
||||
auto animationStatus = animationComponent.gltfAnimations[i];
|
||||
|
||||
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - animationStatus.start).count()) / 1000.0f;
|
||||
auto elapsedInSecs = animationStatus.startOffset + float(std::chrono::duration_cast<std::chrono::milliseconds>(now - animationStatus.start).count()) / 1000.0f;
|
||||
|
||||
if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
#ifndef UNLIT_MATERIAL_PROVIDER_HPP
|
||||
#define UNLIT_MATERIAL_PROVIDER_HPP
|
||||
|
||||
#include <filament/gltfio/MaterialProvider.h>
|
||||
#include <filament/Material.h>
|
||||
#include <filament/MaterialInstance.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
class UnlitMaterialProvider : public filament::gltfio::MaterialProvider {
|
||||
private:
|
||||
filament::Material* mUnlitMaterial;
|
||||
const filament::Material* mMaterials[1];
|
||||
filament::Engine* mEngine;
|
||||
|
||||
public:
|
||||
UnlitMaterialProvider(filament::Engine* engine, const void* const data, const size_t size) : mEngine(engine) {
|
||||
mUnlitMaterial = filament::Material::Builder()
|
||||
.package(data, size)
|
||||
.build(*engine);
|
||||
mMaterials[0] = mUnlitMaterial;
|
||||
}
|
||||
|
||||
~UnlitMaterialProvider() {
|
||||
mEngine->destroy(mUnlitMaterial);
|
||||
}
|
||||
|
||||
filament::MaterialInstance* createMaterialInstance(filament::gltfio::MaterialKey* config,
|
||||
filament::gltfio::UvMap* uvmap,
|
||||
const char* label = "unlit",
|
||||
const char* extras = nullptr) override {
|
||||
auto instance = mUnlitMaterial->createInstance();
|
||||
return instance;
|
||||
}
|
||||
|
||||
filament::Material* getMaterial(filament::gltfio::MaterialKey* config,
|
||||
filament::gltfio::UvMap* uvmap,
|
||||
const char* label = "unlit") override {
|
||||
return mUnlitMaterial;
|
||||
}
|
||||
|
||||
const filament::Material* const* getMaterials() const noexcept override {
|
||||
return mMaterials;
|
||||
}
|
||||
|
||||
size_t getMaterialsCount() const noexcept override {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void destroyMaterials() override {
|
||||
// Materials are destroyed in the destructor
|
||||
}
|
||||
|
||||
bool needsDummyData(filament::VertexAttribute attrib) const noexcept override {
|
||||
// For unlit material, we don't need dummy data for any attribute
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace thermion_filament
|
||||
|
||||
#endif // UNLIT_MATERIAL_PROVIDER_HPP
|
||||
@@ -8,5 +8,5 @@ GIZMO_PACKAGE:
|
||||
GIZMO_GIZMO_OFFSET:
|
||||
.int 0
|
||||
GIZMO_GIZMO_SIZE:
|
||||
.int 26876
|
||||
.int 27809
|
||||
|
||||
|
||||
@@ -8,5 +8,5 @@ _GIZMO_PACKAGE:
|
||||
_GIZMO_GIZMO_OFFSET:
|
||||
.int 0
|
||||
_GIZMO_GIZMO_SIZE:
|
||||
.int 26876
|
||||
.int 27809
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
extern "C" {
|
||||
extern const uint8_t GIZMO_PACKAGE[];
|
||||
extern int GIZMO_GIZMO_OFFSET;
|
||||
extern int GIZMO_GIZMO_SIZE;
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#define GIZMO_GIZMO_DATA (GIZMO_PACKAGE + GIZMO_GIZMO_OFFSET)
|
||||
|
||||
#endif
|
||||
|
||||
12
thermion_dart/native/include/material/grid.S
Normal file
12
thermion_dart/native/include/material/grid.S
Normal file
@@ -0,0 +1,12 @@
|
||||
.global GRID_GRID_OFFSET;
|
||||
.global GRID_GRID_SIZE;
|
||||
|
||||
.global GRID_PACKAGE
|
||||
.section .rodata
|
||||
GRID_PACKAGE:
|
||||
.incbin "grid.bin"
|
||||
GRID_GRID_OFFSET:
|
||||
.int 0
|
||||
GRID_GRID_SIZE:
|
||||
.int 30210
|
||||
|
||||
12
thermion_dart/native/include/material/grid.apple.S
Normal file
12
thermion_dart/native/include/material/grid.apple.S
Normal file
@@ -0,0 +1,12 @@
|
||||
.global _GRID_GRID_OFFSET;
|
||||
.global _GRID_GRID_SIZE;
|
||||
|
||||
.global _GRID_PACKAGE
|
||||
.section __TEXT,__const
|
||||
_GRID_PACKAGE:
|
||||
.incbin "grid.bin"
|
||||
_GRID_GRID_OFFSET:
|
||||
.int 0
|
||||
_GRID_GRID_SIZE:
|
||||
.int 30210
|
||||
|
||||
BIN
thermion_dart/native/include/material/grid.bin
Normal file
BIN
thermion_dart/native/include/material/grid.bin
Normal file
Binary file not shown.
1521
thermion_dart/native/include/material/grid.c
Normal file
1521
thermion_dart/native/include/material/grid.c
Normal file
File diff suppressed because it is too large
Load Diff
13
thermion_dart/native/include/material/grid.h
Normal file
13
thermion_dart/native/include/material/grid.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef GRID_H_
|
||||
#define GRID_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
extern const uint8_t GRID_PACKAGE[];
|
||||
extern int GRID_GRID_OFFSET;
|
||||
extern int GRID_GRID_SIZE;
|
||||
}
|
||||
#define GRID_GRID_DATA (GRID_PACKAGE + GRID_GRID_OFFSET)
|
||||
|
||||
#endif
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,11 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
extern "C" {
|
||||
extern const uint8_t IMAGE_PACKAGE[];
|
||||
extern int IMAGE_IMAGE_OFFSET;
|
||||
extern int IMAGE_IMAGE_SIZE;
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
#define IMAGE_IMAGE_DATA (IMAGE_PACKAGE + IMAGE_IMAGE_OFFSET)
|
||||
|
||||
#endif
|
||||
|
||||
12
thermion_dart/native/include/material/unlit.S
Normal file
12
thermion_dart/native/include/material/unlit.S
Normal file
@@ -0,0 +1,12 @@
|
||||
.global UNLIT_UNLIT_OFFSET;
|
||||
.global UNLIT_UNLIT_SIZE;
|
||||
|
||||
.global UNLIT_PACKAGE
|
||||
.section .rodata
|
||||
UNLIT_PACKAGE:
|
||||
.incbin "unlit.bin"
|
||||
UNLIT_UNLIT_OFFSET:
|
||||
.int 0
|
||||
UNLIT_UNLIT_SIZE:
|
||||
.int 101394
|
||||
|
||||
12
thermion_dart/native/include/material/unlit.apple.S
Normal file
12
thermion_dart/native/include/material/unlit.apple.S
Normal file
@@ -0,0 +1,12 @@
|
||||
.global _UNLIT_UNLIT_OFFSET;
|
||||
.global _UNLIT_UNLIT_SIZE;
|
||||
|
||||
.global _UNLIT_PACKAGE
|
||||
.section __TEXT,__const
|
||||
_UNLIT_PACKAGE:
|
||||
.incbin "unlit.bin"
|
||||
_UNLIT_UNLIT_OFFSET:
|
||||
.int 0
|
||||
_UNLIT_UNLIT_SIZE:
|
||||
.int 101394
|
||||
|
||||
BIN
thermion_dart/native/include/material/unlit.bin
Normal file
BIN
thermion_dart/native/include/material/unlit.bin
Normal file
Binary file not shown.
5080
thermion_dart/native/include/material/unlit.c
Normal file
5080
thermion_dart/native/include/material/unlit.c
Normal file
File diff suppressed because it is too large
Load Diff
13
thermion_dart/native/include/material/unlit.h
Normal file
13
thermion_dart/native/include/material/unlit.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef UNLIT_H_
|
||||
#define UNLIT_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
extern const uint8_t UNLIT_PACKAGE[];
|
||||
extern int UNLIT_UNLIT_OFFSET;
|
||||
extern int UNLIT_UNLIT_SIZE;
|
||||
}
|
||||
#define UNLIT_UNLIT_DATA (UNLIT_PACKAGE + UNLIT_UNLIT_OFFSET)
|
||||
|
||||
#endif
|
||||
194
thermion_dart/native/src/CustomGeometry.cpp
Normal file
194
thermion_dart/native/src/CustomGeometry.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
#include <vector>
|
||||
#include "math.h"
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/Frustum.h>
|
||||
#include <filament/geometry/SurfaceOrientation.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
#include "CustomGeometry.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
using namespace filament;
|
||||
|
||||
CustomGeometry::CustomGeometry(
|
||||
float* vertices,
|
||||
uint32_t numVertices,
|
||||
float* normals,
|
||||
uint32_t numNormals,
|
||||
float* uvs,
|
||||
uint32_t numUvs,
|
||||
uint16_t* indices,
|
||||
uint32_t numIndices,
|
||||
RenderableManager::PrimitiveType primitiveType,
|
||||
Engine* engine)
|
||||
: numVertices(numVertices), numIndices(numIndices), _engine(engine) {
|
||||
this->primitiveType = primitiveType;
|
||||
this->vertices = new float[numVertices];
|
||||
std::memcpy(this->vertices, vertices, numVertices * sizeof(float));
|
||||
|
||||
if(numNormals > 0) {
|
||||
Log("numNormals %d", numNormals);
|
||||
this->normals = new float[numNormals];
|
||||
std::memcpy(this->normals, normals, numNormals * sizeof(float));
|
||||
} else {
|
||||
Log("no normals");
|
||||
}
|
||||
|
||||
if(numUvs > 0) {
|
||||
Log("numUvs %d", numUvs);
|
||||
this->uvs = new float[numUvs];
|
||||
std::memcpy(this->uvs, uvs, numUvs * sizeof(float));
|
||||
} else {
|
||||
this->uvs = nullptr;
|
||||
}
|
||||
|
||||
this->indices = new uint16_t[numIndices];
|
||||
std::memcpy(this->indices, indices, numIndices * sizeof(uint16_t));
|
||||
|
||||
computeBoundingBox();
|
||||
}
|
||||
|
||||
IndexBuffer* CustomGeometry::indexBuffer() const {
|
||||
IndexBuffer::BufferDescriptor::Callback indexCallback = [](void *buf, size_t,
|
||||
void *data)
|
||||
{
|
||||
// free((void *)buf);
|
||||
};
|
||||
|
||||
auto indexBuffer = IndexBuffer::Builder()
|
||||
.indexCount(numIndices)
|
||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||
.build(*_engine);
|
||||
|
||||
indexBuffer->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||
this->indices, indexBuffer->getIndexCount() * sizeof(uint16_t), indexCallback));
|
||||
return indexBuffer;
|
||||
}
|
||||
|
||||
VertexBuffer* CustomGeometry::vertexBuffer() const {
|
||||
VertexBuffer::BufferDescriptor::Callback vertexCallback = [](void *buf, size_t,
|
||||
void *data)
|
||||
{
|
||||
// free((void *)buf);
|
||||
};
|
||||
|
||||
std::vector<filament::math::ushort3> triangles;
|
||||
for(int i=0; i < numIndices; i+=3) {
|
||||
filament::math::ushort3 triangle;
|
||||
triangle.x = this->indices[i];
|
||||
triangle.y = this->indices[i+1];
|
||||
triangle.z = this->indices[i+2];
|
||||
triangles.push_back(triangle);
|
||||
}
|
||||
|
||||
// Create a SurfaceOrientation builder
|
||||
geometry::SurfaceOrientation::Builder builder;
|
||||
builder.vertexCount(numVertices)
|
||||
.normals((filament::math::float3*)normals)
|
||||
.positions((filament::math::float3*)this->vertices)
|
||||
.triangleCount(triangles.size())
|
||||
.triangles(triangles.data());
|
||||
|
||||
// Build the SurfaceOrientation object
|
||||
auto orientation = builder.build();
|
||||
|
||||
// Retrieve the quaternions
|
||||
auto quats = new std::vector<filament::math::quatf>(numVertices);
|
||||
orientation->getQuats(quats->data(), numVertices);
|
||||
|
||||
// Use provided UVs or create dummy UV data
|
||||
std::vector<filament::math::float2>* uvData;
|
||||
if (this->uvs != nullptr) {
|
||||
uvData = new std::vector<filament::math::float2>((filament::math::float2*)this->uvs, (filament::math::float2*)(this->uvs + numVertices * 2));
|
||||
} else {
|
||||
uvData = new std::vector<filament::math::float2>(numVertices, filament::math::float2{0.0f, 0.0f});
|
||||
}
|
||||
|
||||
// Create dummy vertex color data (white color for all vertices)
|
||||
auto dummyColors = new std::vector<filament::math::float4>(numVertices, filament::math::float4{1.0f, 1.0f, 1.0f, 1.0f});
|
||||
|
||||
auto vertexBufferBuilder = VertexBuffer::Builder()
|
||||
.vertexCount(numVertices)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.attribute(VertexAttribute::UV0, 1, VertexBuffer::AttributeType::FLOAT2)
|
||||
.attribute(VertexAttribute::UV1, 2, VertexBuffer::AttributeType::FLOAT2)
|
||||
.attribute(VertexAttribute::COLOR, 3, VertexBuffer::AttributeType::FLOAT4);
|
||||
|
||||
if(this->normals) {
|
||||
vertexBufferBuilder
|
||||
.bufferCount(5)
|
||||
.attribute(VertexAttribute::TANGENTS, 4, filament::VertexBuffer::AttributeType::FLOAT4);
|
||||
} else {
|
||||
vertexBufferBuilder = vertexBufferBuilder.bufferCount(4);
|
||||
}
|
||||
auto vertexBuffer = vertexBufferBuilder
|
||||
.build(*_engine);
|
||||
|
||||
vertexBuffer->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(
|
||||
this->vertices, vertexBuffer->getVertexCount() * sizeof(math::float3), vertexCallback));
|
||||
|
||||
// Set UV0 buffer
|
||||
vertexBuffer->setBufferAt(*_engine, 1, VertexBuffer::BufferDescriptor(
|
||||
uvData->data(), uvData->size() * sizeof(math::float2),
|
||||
[](void* buf, size_t, void* data) {
|
||||
delete static_cast<std::vector<math::float2>*>(data);
|
||||
}, uvData));
|
||||
|
||||
// Set UV1 buffer (reusing UV0 data)
|
||||
vertexBuffer->setBufferAt(*_engine, 2, VertexBuffer::BufferDescriptor(
|
||||
uvData->data(), uvData->size() * sizeof(math::float2),
|
||||
[](void* buf, size_t, void* data) {
|
||||
// Do nothing here, as we're reusing the same data as UV0
|
||||
}, nullptr));
|
||||
|
||||
// Set vertex color buffer
|
||||
vertexBuffer->setBufferAt(*_engine, 3, VertexBuffer::BufferDescriptor(
|
||||
dummyColors->data(), dummyColors->size() * sizeof(math::float4),
|
||||
[](void* buf, size_t, void* data) {
|
||||
delete static_cast<std::vector<math::float4>*>(data);
|
||||
}, dummyColors));
|
||||
|
||||
if(this->normals) {
|
||||
vertexBuffer->setBufferAt(*_engine, 4, VertexBuffer::BufferDescriptor(
|
||||
quats->data(), quats->size() * sizeof(math::quatf), [] (void *buf, size_t,
|
||||
void *data)
|
||||
{
|
||||
delete (std::vector<math::quatf>*)data;
|
||||
}, (void*)quats));
|
||||
}
|
||||
return vertexBuffer;
|
||||
}
|
||||
|
||||
CustomGeometry::~CustomGeometry() {
|
||||
delete[] vertices;
|
||||
delete[] indices;
|
||||
if (normals) delete[] normals;
|
||||
if (uvs) delete[] uvs;
|
||||
}
|
||||
|
||||
void CustomGeometry::computeBoundingBox() {
|
||||
float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
|
||||
float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
|
||||
|
||||
for (uint32_t i = 0; i < numVertices; i += 3) {
|
||||
minX = std::min(vertices[i], minX);
|
||||
minY = std::min(vertices[i + 1], minY);
|
||||
minZ = std::min(vertices[i + 2], minZ);
|
||||
maxX = std::max(vertices[i], maxX);
|
||||
maxY = std::max(vertices[i + 1], maxY);
|
||||
maxZ = std::max(vertices[i + 2], maxZ);
|
||||
}
|
||||
|
||||
boundingBox = Box{{minX, minY, minZ}, {maxX, maxY, maxZ}};
|
||||
}
|
||||
|
||||
Box CustomGeometry::getBoundingBox() const {
|
||||
return boundingBox;
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
354
thermion_dart/native/src/Gizmo.cpp
Normal file
354
thermion_dart/native/src/Gizmo.cpp
Normal file
@@ -0,0 +1,354 @@
|
||||
#include "Gizmo.hpp"
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <utils/Entity.h>
|
||||
#include <utils/EntityManager.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <gltfio/math.h>
|
||||
#include "SceneManager.hpp"
|
||||
#include "material/gizmo.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||
{
|
||||
|
||||
_scene = scene;
|
||||
_view = view;
|
||||
_camera = &(_view->getCamera());
|
||||
|
||||
auto &entityManager = EntityManager::get();
|
||||
|
||||
auto &transformManager = engine.getTransformManager();
|
||||
|
||||
_material =
|
||||
Material::Builder()
|
||||
.package(GIZMO_GIZMO_DATA, GIZMO_GIZMO_SIZE)
|
||||
.build(engine);
|
||||
|
||||
// First, create the black cube at the center
|
||||
// The axes widgets will be parented to this entity
|
||||
_entities[3] = entityManager.create();
|
||||
|
||||
_materialInstances[3] = _material->createInstance();
|
||||
_materialInstances[3]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 1.0f}); // Black color
|
||||
|
||||
// Create center cube vertices
|
||||
float centerCubeSize = 0.01f;
|
||||
float *centerCubeVertices = new float[8 * 3]{
|
||||
-centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||
centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
-centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||
-centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||
centerCubeSize, centerCubeSize, centerCubeSize,
|
||||
-centerCubeSize, centerCubeSize, centerCubeSize};
|
||||
|
||||
// Create center cube indices
|
||||
uint16_t *centerCubeIndices = new uint16_t[36]{
|
||||
0, 1, 2, 2, 3, 0,
|
||||
1, 5, 6, 6, 2, 1,
|
||||
5, 4, 7, 7, 6, 5,
|
||||
4, 0, 3, 3, 7, 4,
|
||||
3, 2, 6, 6, 7, 3,
|
||||
4, 5, 1, 1, 0, 4};
|
||||
|
||||
auto centerCubeVb = VertexBuffer::Builder()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(engine);
|
||||
|
||||
centerCubeVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(engine);
|
||||
centerCubeIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||
centerCubeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
||||
{centerCubeSize, centerCubeSize, centerCubeSize}})
|
||||
.material(0, _materialInstances[3])
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.priority(7)
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||
.culling(false)
|
||||
.build(engine, _entities[3]);
|
||||
|
||||
auto cubeTransformInstance = transformManager.getInstance(_entities[3]);
|
||||
math::mat4f cubeTransform;
|
||||
transformManager.setTransform(cubeTransformInstance, cubeTransform);
|
||||
|
||||
// Line and arrow vertices
|
||||
float lineLength = 0.6f;
|
||||
float lineWidth = 0.004f;
|
||||
float arrowLength = 0.06f;
|
||||
float arrowWidth = 0.02f;
|
||||
float *vertices = new float[13 * 3]{
|
||||
// Line vertices (8 vertices)
|
||||
-lineWidth, -lineWidth, 0.0f,
|
||||
lineWidth, -lineWidth, 0.0f,
|
||||
lineWidth, lineWidth, 0.0f,
|
||||
-lineWidth, lineWidth, 0.0f,
|
||||
-lineWidth, -lineWidth, lineLength,
|
||||
lineWidth, -lineWidth, lineLength,
|
||||
lineWidth, lineWidth, lineLength,
|
||||
-lineWidth, lineWidth, lineLength,
|
||||
// Arrow vertices (5 vertices)
|
||||
0.0f, 0.0f, lineLength + arrowLength, // Tip of the arrow
|
||||
-arrowWidth, -arrowWidth, lineLength, // Base of the arrow
|
||||
arrowWidth, -arrowWidth, lineLength,
|
||||
arrowWidth, arrowWidth, lineLength,
|
||||
-arrowWidth, arrowWidth, lineLength};
|
||||
|
||||
// Line and arrow indices
|
||||
uint16_t *indices = new uint16_t[54]{
|
||||
// Line indices (24 indices)
|
||||
0, 1, 5, 5, 4, 0,
|
||||
1, 2, 6, 6, 5, 1,
|
||||
2, 3, 7, 7, 6, 2,
|
||||
3, 0, 4, 4, 7, 3,
|
||||
// Arrow indices (30 indices)
|
||||
8, 9, 10, // Front face
|
||||
8, 10, 11, // Right face
|
||||
8, 11, 12, // Back face
|
||||
8, 12, 9, // Left face
|
||||
9, 12, 11, 11, 10, 9 // Base of the arrow
|
||||
};
|
||||
|
||||
auto vb = VertexBuffer::Builder()
|
||||
.vertexCount(13)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(engine);
|
||||
|
||||
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto ib = IndexBuffer::Builder().indexCount(54).bufferType(IndexBuffer::IndexType::USHORT).build(engine);
|
||||
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||
indices, 54 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
|
||||
// Create the three axes
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
_entities[i] = entityManager.create();
|
||||
_materialInstances[i] = _material->createInstance();
|
||||
|
||||
auto baseColor = inactiveColors[i];
|
||||
|
||||
math::mat4f transform;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case Axis::X:
|
||||
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 1.0f, 0.0f, 0.0f});
|
||||
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
break;
|
||||
case 1:
|
||||
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 1.0f, 0.0f});
|
||||
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||
break;
|
||||
case 2:
|
||||
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 0.0f, 1.0f});
|
||||
break;
|
||||
}
|
||||
|
||||
_materialInstances[i]->setParameter("color", baseColor);
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-arrowWidth, -arrowWidth, 0},
|
||||
{arrowWidth, arrowWidth, lineLength + arrowLength}})
|
||||
.material(0, _materialInstances[i])
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, 54)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _entities[i]);
|
||||
|
||||
|
||||
auto instance = transformManager.getInstance(_entities[i]);
|
||||
transformManager.setTransform(instance, transform);
|
||||
|
||||
// parent the axis to the center cube
|
||||
transformManager.setParent(instance, cubeTransformInstance);
|
||||
|
||||
}
|
||||
|
||||
createTransparentRectangles();
|
||||
}
|
||||
|
||||
Gizmo::~Gizmo() {
|
||||
_scene->removeEntities(_entities, 7);
|
||||
|
||||
for(int i = 0; i < 7; i++) {
|
||||
_engine.destroy(_entities[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 7; i++) {
|
||||
_engine.destroy(_materialInstances[i]);
|
||||
}
|
||||
|
||||
_engine.destroy(_material);
|
||||
|
||||
}
|
||||
|
||||
void Gizmo::createTransparentRectangles()
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = _engine.getTransformManager();
|
||||
|
||||
float volumeWidth = 0.2f;
|
||||
float volumeLength = 1.2f;
|
||||
float volumeDepth = 0.2f;
|
||||
|
||||
float *volumeVertices = new float[8 * 3]{
|
||||
-volumeWidth / 2, -volumeDepth / 2, 0,
|
||||
volumeWidth / 2, -volumeDepth / 2, 0,
|
||||
volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, volumeDepth / 2, 0,
|
||||
volumeWidth / 2, volumeDepth / 2, 0,
|
||||
volumeWidth / 2, volumeDepth / 2, volumeLength,
|
||||
-volumeWidth / 2, volumeDepth / 2, volumeLength
|
||||
};
|
||||
|
||||
uint16_t *volumeIndices = new uint16_t[36]{
|
||||
0, 1, 2, 2, 3, 0, // Bottom face
|
||||
4, 5, 6, 6, 7, 4, // Top face
|
||||
0, 4, 7, 7, 3, 0, // Left face
|
||||
1, 5, 6, 6, 2, 1, // Right face
|
||||
0, 1, 5, 5, 4, 0, // Front face
|
||||
3, 2, 6, 6, 7, 3 // Back face
|
||||
};
|
||||
|
||||
auto volumeVb = VertexBuffer::Builder()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(_engine);
|
||||
|
||||
volumeVb->setBufferAt(_engine, 0, VertexBuffer::BufferDescriptor(
|
||||
volumeVertices, 8 * sizeof(filament::math::float3),
|
||||
[](void *buffer, size_t size, void *) { delete[] static_cast<float *>(buffer); }
|
||||
));
|
||||
|
||||
auto volumeIb = IndexBuffer::Builder()
|
||||
.indexCount(36)
|
||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||
.build(_engine);
|
||||
|
||||
volumeIb->setBuffer(_engine, IndexBuffer::BufferDescriptor(
|
||||
volumeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *) { delete[] static_cast<uint16_t *>(buffer); }
|
||||
));
|
||||
|
||||
for (int i = 4; i < 7; i++)
|
||||
{
|
||||
_entities[i] = entityManager.create();
|
||||
_materialInstances[i] = _material->createInstance();
|
||||
|
||||
_materialInstances[i]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
||||
|
||||
math::mat4f transform;
|
||||
switch (i-4)
|
||||
{
|
||||
case Axis::X:
|
||||
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||
break;
|
||||
case Axis::Y:
|
||||
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||
break;
|
||||
case Axis::Z:
|
||||
break;
|
||||
}
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
|
||||
.material(0, _materialInstances[i])
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, 36)
|
||||
.priority(7)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(_engine, _entities[i]);
|
||||
|
||||
auto instance = transformManager.getInstance(_entities[i]);
|
||||
transformManager.setTransform(instance, transform);
|
||||
|
||||
// Parent the picking volume to the center cube
|
||||
transformManager.setParent(instance, transformManager.getInstance(_entities[3]));
|
||||
}
|
||||
}
|
||||
|
||||
void Gizmo::highlight(Entity entity) {
|
||||
auto &rm = _engine.getRenderableManager();
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
|
||||
math::float4 baseColor;
|
||||
if(entity == x()) {
|
||||
baseColor = activeColors[Axis::X];
|
||||
} else if(entity == y()) {
|
||||
baseColor = activeColors[Axis::Y];
|
||||
} else if(entity == z()) {
|
||||
baseColor = activeColors[Axis::Z];
|
||||
} else {
|
||||
baseColor = math::float4 { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
}
|
||||
|
||||
materialInstance->setParameter("color", baseColor);
|
||||
|
||||
}
|
||||
|
||||
void Gizmo::unhighlight() {
|
||||
auto &rm = _engine.getRenderableManager();
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto renderableInstance = rm.getInstance(_entities[i]);
|
||||
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
|
||||
math::float4 baseColor = inactiveColors[i];
|
||||
materialInstance->setParameter("color", baseColor);
|
||||
}
|
||||
}
|
||||
|
||||
void Gizmo::pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y))
|
||||
{
|
||||
auto handler = new Gizmo::PickCallbackHandler(this, callback);
|
||||
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||
handler->handle(result);
|
||||
});
|
||||
}
|
||||
|
||||
bool Gizmo::isGizmoEntity(Entity e) {
|
||||
for(int i = 0; i < 7; i++) {
|
||||
if(e == _entities[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Gizmo::setVisibility(bool visible) {
|
||||
if(visible) {
|
||||
_scene->addEntities(_entities, 7);
|
||||
} else {
|
||||
_scene->removeEntities(_entities, 7);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
197
thermion_dart/native/src/GridOverlay.cpp
Normal file
197
thermion_dart/native/src/GridOverlay.cpp
Normal file
@@ -0,0 +1,197 @@
|
||||
#include "GridOverlay.hpp"
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <utils/Entity.h>
|
||||
#include <utils/EntityManager.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <gltfio/math.h>
|
||||
|
||||
#include "material/grid.h"
|
||||
#include "SceneManager.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = engine.getTransformManager();
|
||||
|
||||
const int gridSize = 100;
|
||||
const float gridSpacing = 1.0f;
|
||||
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
|
||||
|
||||
float* gridVertices = new float[vertexCount * 3];
|
||||
int index = 0;
|
||||
|
||||
// Create grid lines
|
||||
for (int i = 0; i <= gridSize; ++i) {
|
||||
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
|
||||
|
||||
// X-axis lines
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||
|
||||
gridVertices[index++] = pos;
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||
|
||||
// Z-axis lines
|
||||
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = pos;
|
||||
|
||||
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||
gridVertices[index++] = 0;
|
||||
gridVertices[index++] = pos;
|
||||
}
|
||||
|
||||
auto vb = VertexBuffer::Builder()
|
||||
.vertexCount(vertexCount)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(engine);
|
||||
|
||||
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(
|
||||
gridVertices, vertexCount * sizeof(filament::math::float3),
|
||||
[](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }
|
||||
));
|
||||
|
||||
uint32_t* gridIndices = new uint32_t[vertexCount];
|
||||
for (uint32_t i = 0; i < vertexCount; ++i) {
|
||||
gridIndices[i] = i;
|
||||
}
|
||||
|
||||
auto ib = IndexBuffer::Builder()
|
||||
.indexCount(vertexCount)
|
||||
.bufferType(IndexBuffer::IndexType::UINT)
|
||||
.build(engine);
|
||||
|
||||
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||
gridIndices, vertexCount * sizeof(uint32_t),
|
||||
[](void* buffer, size_t size, void*) { delete[] static_cast<uint32_t*>(buffer); }
|
||||
));
|
||||
|
||||
_gridEntity = entityManager.create();
|
||||
_material = Material::Builder()
|
||||
.package(GRID_PACKAGE, GRID_GRID_SIZE)
|
||||
.build(engine);
|
||||
|
||||
_materialInstance = _material->createInstance();
|
||||
|
||||
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
|
||||
_materialInstance->setParameter("color", math::float3{0.5f, 0.5f, 0.5f}); // Gray color for the grid
|
||||
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
|
||||
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
|
||||
.material(0, _materialInstance)
|
||||
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _gridEntity);
|
||||
const float sphereRadius = 0.05f;
|
||||
const int sphereSegments = 16;
|
||||
const int sphereRings = 16;
|
||||
|
||||
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
|
||||
int indexCount = sphereRings * sphereSegments * 6;
|
||||
|
||||
math::float3* vertices = new math::float3[vertexCount];
|
||||
uint32_t* indices = new uint32_t[indexCount];
|
||||
|
||||
int vertexIndex = 0;
|
||||
// Generate sphere vertices
|
||||
for (int ring = 0; ring <= sphereRings; ++ring) {
|
||||
float theta = ring * M_PI / sphereRings;
|
||||
float sinTheta = std::sin(theta);
|
||||
float cosTheta = std::cos(theta);
|
||||
|
||||
for (int segment = 0; segment <= sphereSegments; ++segment) {
|
||||
float phi = segment * 2 * M_PI / sphereSegments;
|
||||
float sinPhi = std::sin(phi);
|
||||
float cosPhi = std::cos(phi);
|
||||
|
||||
float x = cosPhi * sinTheta;
|
||||
float y = cosTheta;
|
||||
float z = sinPhi * sinTheta;
|
||||
|
||||
vertices[vertexIndex++] = {x * sphereRadius, y * sphereRadius, z * sphereRadius};
|
||||
}
|
||||
}
|
||||
|
||||
int indexIndex = 0;
|
||||
// Generate sphere indices
|
||||
for (int ring = 0; ring < sphereRings; ++ring) {
|
||||
for (int segment = 0; segment < sphereSegments; ++segment) {
|
||||
uint32_t current = ring * (sphereSegments + 1) + segment;
|
||||
uint32_t next = current + sphereSegments + 1;
|
||||
|
||||
indices[indexIndex++] = current;
|
||||
indices[indexIndex++] = next;
|
||||
indices[indexIndex++] = current + 1;
|
||||
|
||||
indices[indexIndex++] = current + 1;
|
||||
indices[indexIndex++] = next;
|
||||
indices[indexIndex++] = next + 1;
|
||||
}
|
||||
}
|
||||
|
||||
auto sphereVb = VertexBuffer::Builder()
|
||||
.vertexCount(vertexCount)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(engine);
|
||||
|
||||
sphereVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(
|
||||
vertices, vertexCount * sizeof(math::float3),
|
||||
[](void* buffer, size_t size, void*) { delete[] static_cast<math::float3*>(buffer); }
|
||||
));
|
||||
|
||||
auto sphereIb = IndexBuffer::Builder()
|
||||
.indexCount(indexCount)
|
||||
.bufferType(IndexBuffer::IndexType::UINT)
|
||||
.build(engine);
|
||||
|
||||
sphereIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||
indices, indexCount * sizeof(uint32_t),
|
||||
[](void* buffer, size_t size, void*) { delete[] static_cast<uint32_t*>(buffer); }
|
||||
));
|
||||
|
||||
_sphereEntity = entityManager.create();
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
|
||||
{sphereRadius, sphereRadius, sphereRadius}})
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, sphereVb, sphereIb, 0, indexCount)
|
||||
.priority(6)
|
||||
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _sphereEntity);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void GridOverlay::destroy()
|
||||
{
|
||||
auto &rm = _engine.getRenderableManager();
|
||||
auto &tm = _engine.getTransformManager();
|
||||
rm.destroy(_sphereEntity);
|
||||
rm.destroy(_gridEntity);
|
||||
tm.destroy(_sphereEntity);
|
||||
tm.destroy(_gridEntity);
|
||||
_engine.destroy(_sphereEntity);
|
||||
_engine.destroy(_gridEntity);
|
||||
}
|
||||
|
||||
} // namespace thermion_filament
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user