Compare commits
69 Commits
v0.7.0-pre
...
thermion_f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4955837518 | ||
|
|
0e9cf76592 | ||
|
|
368a341b76 | ||
|
|
5cc41a9115 | ||
|
|
368ce83380 | ||
|
|
683b79c9a0 | ||
|
|
81be5e25f7 | ||
|
|
e8e1684694 | ||
|
|
d13ecde7b6 | ||
|
|
08c3af405e | ||
|
|
0571f3e653 | ||
|
|
f351512a78 | ||
|
|
315b898d7c | ||
|
|
c635bd3813 | ||
|
|
b4f9a5c2af | ||
|
|
0222ba2d6c | ||
|
|
a066df55f9 | ||
|
|
aa85dcfa20 | ||
|
|
a3370a775f | ||
|
|
b889fddcfa | ||
|
|
090c36c92b | ||
|
|
9eb2285433 | ||
|
|
c28c518057 | ||
|
|
81ffbdd824 | ||
|
|
55b5c7068e | ||
|
|
78a758f5d4 | ||
|
|
fd19fc1c68 | ||
|
|
cc3020c268 | ||
|
|
6902c27d02 | ||
|
|
0ec7e2af95 | ||
|
|
c6c918907a | ||
|
|
d3891e481e | ||
|
|
563ffd2902 | ||
|
|
2ce5cb1f62 | ||
|
|
842c6b1581 | ||
|
|
b833b2d288 | ||
|
|
013730b108 | ||
|
|
846f45bb63 | ||
|
|
735612af66 | ||
|
|
e823083e86 | ||
|
|
ae15f2114e | ||
|
|
cb17bf0ffd | ||
|
|
84101b457f | ||
|
|
aefedf8c00 | ||
|
|
ab793387bc | ||
|
|
534e5b46a8 | ||
|
|
3468e7da55 | ||
|
|
1f58717635 | ||
|
|
7dc0e91e6b | ||
|
|
49b8e7023b | ||
|
|
a455e4f88a | ||
|
|
3785580b01 | ||
|
|
6cfa86fe75 | ||
|
|
dc70909715 | ||
|
|
89f49f98c4 | ||
|
|
025e39318d | ||
|
|
cfa7805970 | ||
|
|
31e68df1c5 | ||
|
|
8e75555540 | ||
|
|
c8fa220362 | ||
|
|
8e892a1f23 | ||
|
|
ee8769b7d7 | ||
|
|
7ecf097861 | ||
|
|
4f4be9b7d7 | ||
|
|
338fe3bb9f | ||
|
|
04b1498cd9 | ||
|
|
1d3dab88d1 | ||
|
|
ec16f97023 | ||
|
|
436b978537 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,3 +7,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
**/*/build
|
**/*/build
|
||||||
**/*/pubspec.lock
|
**/*/pubspec.lock
|
||||||
|
pubspec_overrides.yaml
|
||||||
|
/pubspec.lock
|
||||||
|
*.iml
|
||||||
|
|||||||
307
CHANGELOG.md
Normal file
307
CHANGELOG.md
Normal file
@@ -0,0 +1,307 @@
|
|||||||
|
# Change Log
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## 2024-06-26
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.1+2`](#thermion_dart---v0112)
|
||||||
|
- [`thermion_flutter` - `v0.1.1+7`](#thermion_flutter---v0117)
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0+6`](#thermion_flutter_ffi---v0106)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0+6`](#thermion_flutter_platform_interface---v0106)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1+6`](#thermion_flutter_web---v0016)
|
||||||
|
|
||||||
|
Packages graduated to a stable release (see pre-releases prior to the stable version for changelog entries):
|
||||||
|
|
||||||
|
- `thermion_dart` - `v0.1.1+2`
|
||||||
|
- `thermion_flutter` - `v0.1.1+7`
|
||||||
|
- `thermion_flutter_ffi` - `v0.1.0+6`
|
||||||
|
- `thermion_flutter_platform_interface` - `v0.1.0+6`
|
||||||
|
- `thermion_flutter_web` - `v0.0.1+6`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.1+2`
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.1.1+7`
|
||||||
|
|
||||||
|
#### `thermion_flutter_ffi` - `v0.1.0+6`
|
||||||
|
|
||||||
|
#### `thermion_flutter_platform_interface` - `v0.1.0+6`
|
||||||
|
|
||||||
|
#### `thermion_flutter_web` - `v0.0.1+6`
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-26
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.1-dev.0+2`](#thermion_dart---v011-dev02)
|
||||||
|
- [`thermion_flutter` - `v0.1.1-dev.0+7`](#thermion_flutter---v011-dev07)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0-dev.0+6`](#thermion_flutter_platform_interface---v010-dev06)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1-dev.0+6`](#thermion_flutter_web---v001-dev06)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0-dev.0+6`](#thermion_flutter_ffi---v010-dev06)
|
||||||
|
|
||||||
|
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-dev.0+6`
|
||||||
|
- `thermion_flutter_web` - `v0.0.1-dev.0+6`
|
||||||
|
- `thermion_flutter_ffi` - `v0.1.0-dev.0+6`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.1-dev.0+2`
|
||||||
|
|
||||||
|
- **FIX**: revert to std::thread (pthreads not easily available on Windows).
|
||||||
|
- **FIX**: on Windows, pass static libs via -l rather than custom linkWith property so build.dart stays compatible between published & custom versions.
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.1.1-dev.0+7`
|
||||||
|
|
||||||
|
- **FIX**: add ResourceBuffer header directly to Windows build so I don't have to fiddle around getting the CMake path right.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-22
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.1+1`](#thermion_dart---v0111)
|
||||||
|
- [`thermion_flutter` - `v0.1.1+6`](#thermion_flutter---v0116)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1+5`](#thermion_flutter_web---v0015)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0+5`](#thermion_flutter_platform_interface---v0105)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0+5`](#thermion_flutter_ffi---v0105)
|
||||||
|
|
||||||
|
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+5`
|
||||||
|
- `thermion_flutter_platform_interface` - `v0.1.0+5`
|
||||||
|
- `thermion_flutter_ffi` - `v0.1.0+5`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.1+1`
|
||||||
|
|
||||||
|
- **DOCS**: update with links to playground.
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.1.1+6`
|
||||||
|
|
||||||
|
- **DOCS**: update with links to playground.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-21
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.1`](#thermion_dart---v011)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.1`
|
||||||
|
|
||||||
|
- Bump "thermion_dart" to `0.1.1`.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-21
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.0+4`](#thermion_dart---v0104)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1+4`](#thermion_flutter_web---v0014)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0+4`](#thermion_flutter_platform_interface---v0104)
|
||||||
|
- [`thermion_flutter` - `v0.1.1+5`](#thermion_flutter---v0115)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0+4`](#thermion_flutter_ffi---v0104)
|
||||||
|
|
||||||
|
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+4`
|
||||||
|
- `thermion_flutter_platform_interface` - `v0.1.0+4`
|
||||||
|
- `thermion_flutter` - `v0.1.1+5`
|
||||||
|
- `thermion_flutter_ffi` - `v0.1.0+4`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.0+4`
|
||||||
|
|
||||||
|
- **FIX**: add dummy asset to build.dart on Linux builds so we can use the package on a Linux host.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-21
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.0+3`](#thermion_dart---v0103)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1+3`](#thermion_flutter_web---v0013)
|
||||||
|
- [`thermion_flutter` - `v0.1.1+4`](#thermion_flutter---v0114)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0+3`](#thermion_flutter_platform_interface---v0103)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0+3`](#thermion_flutter_ffi---v0103)
|
||||||
|
|
||||||
|
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+3`
|
||||||
|
- `thermion_flutter` - `v0.1.1+4`
|
||||||
|
- `thermion_flutter_platform_interface` - `v0.1.0+3`
|
||||||
|
- `thermion_flutter_ffi` - `v0.1.0+3`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.0+3`
|
||||||
|
|
||||||
|
- **FIX**: exit build.dart early on Linux builds so we can use the package on a Linux host.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-21
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.0+2`](#thermion_dart---v0102)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0+2`](#thermion_flutter_ffi---v0102)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1+2`](#thermion_flutter_web---v0012)
|
||||||
|
- [`thermion_flutter` - `v0.1.1+3`](#thermion_flutter---v0113)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0+2`](#thermion_flutter_platform_interface---v0102)
|
||||||
|
|
||||||
|
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+2`
|
||||||
|
- `thermion_flutter` - `v0.1.1+3`
|
||||||
|
- `thermion_flutter_platform_interface` - `v0.1.0+2`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.0+2`
|
||||||
|
|
||||||
|
- **REFACTOR**: rearrange some stubs/imports for easier web WASM deployment.
|
||||||
|
|
||||||
|
#### `thermion_flutter_ffi` - `v0.1.0+2`
|
||||||
|
|
||||||
|
- **REFACTOR**: rearrange some stubs/imports for easier web WASM deployment.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-21
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_flutter` - `v0.1.1+2`](#thermion_flutter---v0112)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.1.1+2`
|
||||||
|
|
||||||
|
- **FIX**: update Flutter example project to use new API.
|
||||||
|
- **FIX**: add logging dependency to thermion_flutter.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-06-21
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- There are no breaking changes in this release.
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.1.0+1`](#thermion_dart---v0101)
|
||||||
|
- [`thermion_flutter` - `v0.1.1+1`](#thermion_flutter---v0111)
|
||||||
|
- [`thermion_flutter_web` - `v0.0.1+1`](#thermion_flutter_web---v0011)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.1.0+1`](#thermion_flutter_platform_interface---v0101)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.1.0+1`](#thermion_flutter_ffi---v0101)
|
||||||
|
|
||||||
|
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+1`
|
||||||
|
- `thermion_flutter_ffi` - `v0.1.0+1`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.1.0+1`
|
||||||
|
|
||||||
|
- **REFACTOR**: export ThermionViewerWasm for web and hide FFI/WASM version.
|
||||||
|
- **FIX**: use preserveDrawingBuffer=true on web.
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.1.1+1`
|
||||||
|
|
||||||
|
- **REFACTOR**: export ThermionViewerWasm for web and hide FFI/WASM version.
|
||||||
|
- **FIX**: catch exception if gizmo unavailable in ThermionGestureDestectorDesktop.
|
||||||
|
|
||||||
|
#### `thermion_flutter_web` - `v0.0.1+1`
|
||||||
|
|
||||||
|
- **REFACTOR**: export ThermionViewerWasm for web and hide FFI/WASM version.
|
||||||
|
|
||||||
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2024 Nick Fisher
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
@@ -1,9 +1,10 @@
|
|||||||

|

|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://docs.page/nmfisher/flutter_filament/quickstart">Quickstart (Flutter)</a> •
|
<a href="https://docs.page/nmfisher/thermion/quickstart">Quickstart (Flutter)</a> •
|
||||||
<a href="https://docs.page/nmfisher/flutter_filament">Documentation</a> •
|
<a href="https://docs.page/nmfisher/thermion">Documentation</a> •
|
||||||
<a href="https://github.com/nmfisher/thermion/docs/examples/">Showcase</a> •
|
<a href="https://docs.page/nmfisher/thermion/examples">Showcase</a> •
|
||||||
|
<a href="https://dartpad.thermion.dev/">Playground</a> •
|
||||||
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,15 @@
|
|||||||
"Getting Started",
|
"Getting Started",
|
||||||
[
|
[
|
||||||
["Overview", "/"],
|
["Overview", "/"],
|
||||||
["Quick Start", "/quickstart"]
|
["Quick Start", "/quickstart"],
|
||||||
|
["Playground", "https://dartpad.thermion.dev"]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
["Misc.", [["Contributing", "/contributing"]]]
|
["Misc.", [
|
||||||
|
["Windows", "/windows"],
|
||||||
|
["Android", "/android"],
|
||||||
|
["Contributing", "/contributing"]
|
||||||
|
]]
|
||||||
]
|
]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,3 +4,7 @@ Thermion is an open source project and we welcome all contributions from every l
|
|||||||
|
|
||||||
Please [join us on Discord](https://discord.gg/h2VdDK3EAQ) if you'd like some guidance or just want to chat.
|
Please [join us on Discord](https://discord.gg/h2VdDK3EAQ) if you'd like some guidance or just want to chat.
|
||||||
|
|
||||||
|
##
|
||||||
|
|
||||||
|
We are now using [Melos](https://melos.invertase.dev/) to manage the repository. This lets us auto-generate changelogs & versioning from commit messages, so if you wish to submit a PR, please use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 78 KiB |
@@ -204,6 +204,8 @@ The cube still won't be visible until we add a light to the scene and tell Therm
|
|||||||
$ flutter run -d macos
|
$ flutter run -d macos
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> You may experience a noticeable delay the very first time you run the project. Don't panic, it's not frozen! This is due to the build system downloading the prebuilt Filament binaries from Cloudflare, which can take some time (particularly on Windows). These binaries will be cached after first download, so subsequent runs will be much faster (though every time you run flutter clean, the binaries will be re-downloaded).
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Your first Thermion project is complete!
|
Your first Thermion project is complete!
|
||||||
@@ -1,15 +1,29 @@
|
|||||||
## Windows
|
## Windows
|
||||||
|
|
||||||
|
## CMakeLists
|
||||||
|
|
||||||
|
You will need to disable the `/WX` compiler flag.
|
||||||
|
|
||||||
|
In your project, open the `windows/CMakeList.txt` file and find the following line:
|
||||||
|
|
||||||
|
`target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")`
|
||||||
|
|
||||||
|
Delete the `/WX`:
|
||||||
|
|
||||||
|
`target_compile_options(${TARGET} PRIVATE /W4 /wd"4100")`
|
||||||
|
|
||||||
|
|
||||||
## pubspec.yaml
|
## pubspec.yaml
|
||||||
|
|
||||||
On Windows, you will need to add a custom version of `native_toolchain_c` to your `dependency_overrides`. This is currently needed to link static libraries when building a DLL.
|
On Windows, you will need to add a custom version of `native_toolchain_c` to your `dependency_overrides`. This is currently needed to link static libraries when building a DLL.
|
||||||
|
|
||||||
```
|
```
|
||||||
native_toolchain_c:
|
dependency_overrides:
|
||||||
|
native_toolchain_c:
|
||||||
git:
|
git:
|
||||||
url: git@github.com:nmfisher/native.git
|
url: https://github.com/nmfisher/native.git
|
||||||
path: pkgs/native_toolchain_c
|
path: pkgs/native_toolchain_c
|
||||||
ref: 99020084c4687be4c58c7115a167088c0441d1de
|
ref: windows_dll_fix
|
||||||
```
|
```
|
||||||
|
|
||||||
This will eventually be fixed upstream in the `native_toolchain_c` package, so this should be a short-term/temporary issue only.
|
This will eventually be fixed upstream in the `native_toolchain_c` package, so this should be a short-term/temporary issue only.
|
||||||
|
|||||||
@@ -1,36 +1,34 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:thermion_flutter/filament/widgets/camera/entity_controller_mouse_widget.dart';
|
import 'package:thermion_flutter/thermion/widgets/camera/entity_controller_mouse_widget.dart';
|
||||||
import 'package:thermion_flutter/filament/widgets/camera/gestures/filament_gesture_detector.dart';
|
|
||||||
import 'package:thermion_flutter/filament/widgets/filament_widget.dart';
|
|
||||||
import 'package:thermion_flutter/thermion_flutter.dart';
|
import 'package:thermion_flutter/thermion_flutter.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/entities/entity_transform_controller.dart';
|
import 'package:thermion_dart/thermion_dart/entities/entity_transform_controller.dart';
|
||||||
|
|
||||||
|
|
||||||
class ExampleViewport extends StatelessWidget {
|
class ExampleViewport extends StatelessWidget {
|
||||||
final ThermionFlutterPlugin? controller;
|
final ThermionViewer? viewer;
|
||||||
final EntityTransformController? entityTransformController;
|
final EntityTransformController? entityTransformController;
|
||||||
final EdgeInsets padding;
|
final EdgeInsets padding;
|
||||||
final FocusNode keyboardFocusNode;
|
final FocusNode keyboardFocusNode;
|
||||||
|
|
||||||
const ExampleViewport(
|
const ExampleViewport(
|
||||||
{super.key,
|
{super.key,
|
||||||
required this.controller,
|
required this.viewer,
|
||||||
required this.padding,
|
required this.padding,
|
||||||
required this.keyboardFocusNode,
|
required this.keyboardFocusNode,
|
||||||
this.entityTransformController});
|
this.entityTransformController});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return controller != null
|
return viewer != null
|
||||||
? Padding(
|
? Padding(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
child: EntityTransformMouseControllerWidget(
|
child: EntityTransformMouseControllerWidget(
|
||||||
transformController: entityTransformController,
|
transformController: entityTransformController,
|
||||||
child: FilamentGestureDetector(
|
child: ThermionGestureDetector(
|
||||||
showControlOverlay: true,
|
showControlOverlay: true,
|
||||||
controller: controller!.viewer,
|
controller: viewer!,
|
||||||
child: ThermionWidget(
|
child: ThermionWidget(
|
||||||
plugin: controller!,
|
viewer: viewer!,
|
||||||
))))
|
))))
|
||||||
: Container();
|
: Container();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,10 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:thermion_flutter/filament/widgets/debug/entity_list_widget.dart';
|
import 'package:thermion_flutter/thermion/widgets/debug/entity_list_widget.dart';
|
||||||
import 'package:thermion_flutter_example/camera_matrix_overlay.dart';
|
|
||||||
import 'package:thermion_flutter_example/menus/controller_menu.dart';
|
import 'package:thermion_flutter_example/menus/controller_menu.dart';
|
||||||
import 'package:thermion_flutter_example/example_viewport.dart';
|
import 'package:thermion_flutter_example/example_viewport.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/entities/entity_transform_controller.dart';
|
|
||||||
import 'package:thermion_flutter_example/menus/scene_menu.dart';
|
import 'package:thermion_flutter_example/menus/scene_menu.dart';
|
||||||
import 'package:thermion_flutter/thermion_flutter.dart';
|
import 'package:thermion_flutter/thermion_flutter.dart';
|
||||||
import 'package:thermion_flutter_example/picker_result_widget.dart';
|
|
||||||
|
|
||||||
|
|
||||||
const loadDefaultScene = bool.hasEnvironment('--load-default-scene');
|
const loadDefaultScene = bool.hasEnvironment('--load-default-scene');
|
||||||
|
|
||||||
@@ -38,8 +34,7 @@ class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
|
|||||||
bodyMedium: TextStyle(fontSize: 12))),
|
bodyMedium: TextStyle(fontSize: 12))),
|
||||||
// showPerformanceOverlay: true,
|
// showPerformanceOverlay: true,
|
||||||
home: const Scaffold(
|
home: const Scaffold(
|
||||||
backgroundColor: Color(0x00000000),
|
backgroundColor: Color(0x00000000), body: ExampleWidget()));
|
||||||
body: ExampleWidget()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +50,7 @@ class ExampleWidget extends StatefulWidget {
|
|||||||
enum MenuType { controller, assets, camera, misc }
|
enum MenuType { controller, assets, camera, misc }
|
||||||
|
|
||||||
class ExampleWidgetState extends State<ExampleWidget> {
|
class ExampleWidgetState extends State<ExampleWidget> {
|
||||||
final _plugin = ThermionFlutterPlugin();
|
ThermionViewer? _viewer;
|
||||||
|
|
||||||
EdgeInsets _viewportMargin = EdgeInsets.zero;
|
EdgeInsets _viewportMargin = EdgeInsets.zero;
|
||||||
|
|
||||||
@@ -99,105 +94,103 @@ class ExampleWidgetState extends State<ExampleWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder(
|
return Stack(fit: StackFit.expand, children: [
|
||||||
future: _plugin.initialized,
|
if (_viewer != null)
|
||||||
builder: (_, AsyncSnapshot<bool> initialized) {
|
Positioned.fill(
|
||||||
var isInitialized = initialized.data == true;
|
child: ExampleViewport(
|
||||||
|
viewer: _viewer!,
|
||||||
return Stack(
|
entityTransformController: _transformController,
|
||||||
fit: StackFit.expand,
|
padding: _viewportMargin,
|
||||||
children: [
|
keyboardFocusNode: _sharedFocusNode),
|
||||||
if (isInitialized)
|
),
|
||||||
Positioned.fill(
|
Positioned(
|
||||||
child: ExampleViewport(
|
bottom: 30,
|
||||||
controller: isInitialized ? _plugin : null,
|
left: 0,
|
||||||
entityTransformController: _transformController,
|
right: 10,
|
||||||
padding: _viewportMargin,
|
height: 30,
|
||||||
keyboardFocusNode: _sharedFocusNode),
|
child: Container(
|
||||||
|
height: 30,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(30),
|
||||||
|
color: Colors.white.withOpacity(0.25),
|
||||||
),
|
),
|
||||||
Positioned(
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
bottom: 30,
|
child:
|
||||||
left: 0,
|
Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
|
||||||
right: 10,
|
ViewerMenu(
|
||||||
height: 30,
|
sharedFocusNode: _sharedFocusNode,
|
||||||
child: Container(
|
viewer: _viewer,
|
||||||
height: 30,
|
onToggleViewport: () {
|
||||||
decoration: BoxDecoration(
|
setState(() {
|
||||||
borderRadius: BorderRadius.circular(30),
|
_viewportMargin = (_viewportMargin == EdgeInsets.zero)
|
||||||
color: Colors.white.withOpacity(0.25),
|
? const EdgeInsets.all(30)
|
||||||
),
|
: EdgeInsets.zero;
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
});
|
||||||
child: Row(
|
},
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
onViewerDestroyed: () {
|
||||||
children: [
|
setState(() {
|
||||||
ControllerMenu(
|
_viewer = null;
|
||||||
sharedFocusNode: _sharedFocusNode,
|
});
|
||||||
controller: _plugin,
|
},
|
||||||
onToggleViewport: () {
|
onViewerCreated: (v) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_viewportMargin =
|
_viewer = v;
|
||||||
(_viewportMargin == EdgeInsets.zero)
|
});
|
||||||
? const EdgeInsets.all(30)
|
}),
|
||||||
: EdgeInsets.zero;
|
SceneMenu(
|
||||||
});
|
sharedFocusNode: _sharedFocusNode,
|
||||||
},
|
controller: _viewer,
|
||||||
onControllerDestroyed: () {},
|
),
|
||||||
onControllerCreated: () {}),
|
GestureDetector(
|
||||||
SceneMenu(
|
onTap: () async {
|
||||||
sharedFocusNode: _sharedFocusNode,
|
await _viewer!
|
||||||
controller: _plugin,
|
.loadGlb('assets/shapes/shapes.glb', numInstances: 1);
|
||||||
),
|
},
|
||||||
GestureDetector(
|
child: Container(
|
||||||
onTap: () async {
|
color: Colors.transparent,
|
||||||
await _plugin.viewer.loadGlb(
|
child: const Text("shapes.glb"))),
|
||||||
'assets/shapes/shapes.glb',
|
const SizedBox(width: 5),
|
||||||
numInstances: 1);
|
GestureDetector(
|
||||||
},
|
onTap: () async {
|
||||||
child: Container(
|
await _viewer!.loadGlb('assets/1.glb');
|
||||||
color: Colors.transparent,
|
},
|
||||||
child: const Text("shapes.glb"))),
|
child: Container(
|
||||||
const SizedBox(width: 5),
|
color: Colors.transparent, child: const Text("1.glb"))),
|
||||||
GestureDetector(
|
const SizedBox(width: 5),
|
||||||
onTap: () async {
|
GestureDetector(
|
||||||
await _plugin.viewer.loadGlb('assets/1.glb');
|
onTap: () async {
|
||||||
},
|
await _viewer!.loadGlb('assets/2.glb');
|
||||||
child: Container(
|
},
|
||||||
color: Colors.transparent,
|
child: Container(
|
||||||
child: const Text("1.glb"))),
|
color: Colors.transparent, child: const Text("2.glb"))),
|
||||||
const SizedBox(width: 5),
|
const SizedBox(width: 5),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
await _plugin.viewer.loadGlb('assets/2.glb');
|
await _viewer!.loadGlb('assets/3.glb');
|
||||||
},
|
},
|
||||||
child: Container(
|
child: Container(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent, child: const Text("3.glb"))),
|
||||||
child: const Text("2.glb"))),
|
Expanded(child: Container()),
|
||||||
const SizedBox(width: 5),
|
]))),
|
||||||
GestureDetector(
|
if (_viewer != null) ...[
|
||||||
onTap: () async {
|
Positioned(
|
||||||
await _plugin.viewer.loadGlb('assets/3.glb');
|
top: 10,
|
||||||
},
|
left: 10,
|
||||||
child: Container(
|
width: 200,
|
||||||
color: Colors.transparent,
|
height: 200,
|
||||||
child: const Text("3.glb"))),
|
child: Container(child: EntityListWidget(controller: _viewer!))),
|
||||||
Expanded(child: Container()),
|
// Padding(
|
||||||
]))),
|
// padding: const EdgeInsets.only(top: 10, left: 20, right: 20),
|
||||||
if (isInitialized) ...[
|
// child: ValueListenableBuilder(
|
||||||
Positioned(top:10, left:10, width:200, height:200, child:Container(
|
// valueListenable: showProjectionMatrices,
|
||||||
child:EntityListWidget(controller: _plugin.viewer))),
|
// builder: (ctx, value, child) => CameraMatrixOverlay(
|
||||||
// Padding(
|
// controller: _viewer!, showProjectionMatrices: value)),
|
||||||
// padding: const EdgeInsets.only(top: 10, left: 20, right: 20),
|
// ),
|
||||||
// child: ValueListenableBuilder(
|
// Align(
|
||||||
// valueListenable: showProjectionMatrices,
|
// alignment: Alignment.topRight,
|
||||||
// builder: (ctx, value, child) => CameraMatrixOverlay(
|
// child: PickerResultWidget(controller: _viewer!),
|
||||||
// controller: _plugin.viewer, showProjectionMatrices: value)),
|
// )
|
||||||
// ),
|
]
|
||||||
// Align(
|
]);
|
||||||
// alignment: Alignment.topRight,
|
|
||||||
// child: PickerResultWidget(controller: _plugin.viewer),
|
|
||||||
// )
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import 'package:vector_math/vector_math_64.dart' as v;
|
|||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
|
|
||||||
class AssetSubmenu extends StatefulWidget {
|
class AssetSubmenu extends StatefulWidget {
|
||||||
final ThermionFlutterPlugin controller;
|
final ThermionViewer viewer;
|
||||||
const AssetSubmenu({super.key, required this.controller});
|
const AssetSubmenu({super.key, required this.viewer});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _AssetSubmenuState();
|
State<StatefulWidget> createState() => _AssetSubmenuState();
|
||||||
@@ -26,8 +26,8 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
closeOnActivate: false,
|
closeOnActivate: false,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var entity = await widget.controller.viewer.getChildEntity(
|
var entity = await widget.viewer.getChildEntity(
|
||||||
widget.controller.viewer.scene.listEntities().last, "Cylinder");
|
widget.viewer.scene.listEntities().last, "Cylinder");
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@@ -39,8 +39,8 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
child: const Text('Find Cylinder entity by name')),
|
child: const Text('Find Cylinder entity by name')),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
widget.controller.viewer.setPosition(
|
widget.viewer.setPosition(
|
||||||
widget.controller.viewer.scene.listEntities().last,
|
widget.viewer.scene.listEntities().last,
|
||||||
1.0,
|
1.0,
|
||||||
1.0,
|
1.0,
|
||||||
-1.0);
|
-1.0);
|
||||||
@@ -50,8 +50,8 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final color = Colors.purple;
|
final color = Colors.purple;
|
||||||
widget.controller.viewer.setMaterialColor(
|
widget.viewer.setMaterialColor(
|
||||||
widget.controller.viewer.scene.listEntities().last,
|
widget.viewer.scene.listEntities().last,
|
||||||
"Cone",
|
"Cone",
|
||||||
0,
|
0,
|
||||||
color.red / 255.0,
|
color.red / 255.0,
|
||||||
@@ -85,14 +85,14 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
-1.0,
|
-1.0,
|
||||||
];
|
];
|
||||||
var indices = [0, 1, 2, 2, 3, 0];
|
var indices = [0, 1, 2, 2, 3, 0];
|
||||||
var geom = await widget.controller.viewer.createGeometry(
|
var geom = await widget.viewer.createGeometry(
|
||||||
verts, indices,
|
verts, indices,
|
||||||
materialPath: "asset://assets/solidcolor.filamat");
|
materialPath: "asset://assets/solidcolor.filamat");
|
||||||
},
|
},
|
||||||
child: const Text("Quad")),
|
child: const Text("Quad")),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await widget.controller.viewer.createGeometry([
|
await widget.viewer.createGeometry([
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
@@ -118,14 +118,14 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
_geometrySubmenu(),
|
_geometrySubmenu(),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await widget.controller.viewer.addLight(
|
await widget.viewer.addLight(
|
||||||
LightType.DIRECTIONAL, 6500, 100000, 0, 1, 0, 0, -1, 0);
|
LightType.DIRECTIONAL, 6500, 100000, 0, 1, 0, 0, -1, 0);
|
||||||
},
|
},
|
||||||
child: const Text("Add directional light"),
|
child: const Text("Add directional light"),
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await widget.controller.viewer.addLight(
|
await widget.viewer.addLight(
|
||||||
LightType.POINT, 6500, 100000, 0, 1, 0, 0, -1, 0,
|
LightType.POINT, 6500, 100000, 0, 1, 0, 0, -1, 0,
|
||||||
falloffRadius: 1.0);
|
falloffRadius: 1.0);
|
||||||
},
|
},
|
||||||
@@ -133,7 +133,7 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await widget.controller.viewer.addLight(
|
await widget.viewer.addLight(
|
||||||
LightType.SPOT, 6500, 1000000, 0, 0, 0, 0, 1, 0,
|
LightType.SPOT, 6500, 1000000, 0, 0, 0, 0, 1, 0,
|
||||||
spotLightConeInner: 0.1,
|
spotLightConeInner: 0.1,
|
||||||
spotLightConeOuter: 0.4,
|
spotLightConeOuter: 0.4,
|
||||||
@@ -143,26 +143,26 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await widget.controller.viewer.clearLights();
|
await widget.viewer.clearLights();
|
||||||
},
|
},
|
||||||
child: const Text("Clear lights"),
|
child: const Text("Clear lights"),
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
final color = const Color(0xAA73C9FA);
|
final color = const Color(0xAA73C9FA);
|
||||||
widget.controller.viewer.setBackgroundColor(color.red / 255.0,
|
widget.viewer.setBackgroundColor(color.red / 255.0,
|
||||||
color.green / 255.0, color.blue / 255.0, 1.0);
|
color.green / 255.0, color.blue / 255.0, 1.0);
|
||||||
},
|
},
|
||||||
child: const Text("Set background color")),
|
child: const Text("Set background color")),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer
|
widget.viewer
|
||||||
.setBackgroundImage('assets/background.ktx');
|
.setBackgroundImage('assets/background.ktx');
|
||||||
},
|
},
|
||||||
child: const Text("Load background image")),
|
child: const Text("Load background image")),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.setBackgroundImage(
|
widget.viewer.setBackgroundImage(
|
||||||
'assets/background.ktx',
|
'assets/background.ktx',
|
||||||
fillHeight: true);
|
fillHeight: true);
|
||||||
},
|
},
|
||||||
@@ -170,9 +170,9 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (ExampleWidgetState.hasSkybox) {
|
if (ExampleWidgetState.hasSkybox) {
|
||||||
widget.controller.viewer.removeSkybox();
|
widget.viewer.removeSkybox();
|
||||||
} else {
|
} else {
|
||||||
widget.controller.viewer
|
widget.viewer
|
||||||
.loadSkybox('assets/default_env/default_env_skybox.ktx');
|
.loadSkybox('assets/default_env/default_env_skybox.ktx');
|
||||||
}
|
}
|
||||||
ExampleWidgetState.hasSkybox = !ExampleWidgetState.hasSkybox;
|
ExampleWidgetState.hasSkybox = !ExampleWidgetState.hasSkybox;
|
||||||
@@ -182,18 +182,18 @@ class _AssetSubmenuState extends State<AssetSubmenu> {
|
|||||||
: 'Load skybox')),
|
: 'Load skybox')),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer
|
widget.viewer
|
||||||
.loadIbl('assets/default_env/default_env_ibl.ktx');
|
.loadIbl('assets/default_env/default_env_ibl.ktx');
|
||||||
},
|
},
|
||||||
child: const Text('Load IBL')),
|
child: const Text('Load IBL')),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.removeIbl();
|
widget.viewer.removeIbl();
|
||||||
},
|
},
|
||||||
child: const Text('Remove IBL')),
|
child: const Text('Remove IBL')),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await widget.controller.viewer.clearEntities();
|
await widget.viewer.clearEntities();
|
||||||
},
|
},
|
||||||
child: const Text('Clear assets')),
|
child: const Text('Clear assets')),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
|||||||
import 'package:thermion_flutter_example/main.dart';
|
import 'package:thermion_flutter_example/main.dart';
|
||||||
|
|
||||||
class CameraSubmenu extends StatefulWidget {
|
class CameraSubmenu extends StatefulWidget {
|
||||||
final ThermionFlutterPlugin controller;
|
final ThermionViewer viewer;
|
||||||
const CameraSubmenu({super.key, required this.controller});
|
const CameraSubmenu({super.key, required this.viewer});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _CameraSubmenuState();
|
State<StatefulWidget> createState() => _CameraSubmenuState();
|
||||||
@@ -22,10 +22,10 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
widget.controller.viewer.initialized.then((_) {
|
widget.viewer.initialized.then((_) {
|
||||||
widget.controller.viewer.getCameraCullingNear().then((v) {
|
widget.viewer.getCameraCullingNear().then((v) {
|
||||||
_near = v;
|
_near = v;
|
||||||
widget.controller.viewer.getCameraCullingFar().then((v) {
|
widget.viewer.getCameraCullingFar().then((v) {
|
||||||
_far = v;
|
_far = v;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
@@ -56,7 +56,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
menuChildren: [1.0, 7.0, 14.0, 28.0, 56.0]
|
menuChildren: [1.0, 7.0, 14.0, 28.0, 56.0]
|
||||||
.map((v) => MenuItemButton(
|
.map((v) => MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.setCameraFocalLength(v);
|
widget.viewer.setCameraFocalLength(v);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
v.toStringAsFixed(2),
|
v.toStringAsFixed(2),
|
||||||
@@ -71,7 +71,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
_near = v;
|
_near = v;
|
||||||
print("Setting camera culling to $_near $_far!");
|
print("Setting camera culling to $_near $_far!");
|
||||||
|
|
||||||
widget.controller.viewer.setCameraCulling(_near!, _far!);
|
widget.viewer.setCameraCulling(_near!, _far!);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
v.toStringAsFixed(2),
|
v.toStringAsFixed(2),
|
||||||
@@ -85,7 +85,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
_far = v;
|
_far = v;
|
||||||
print("Setting camera culling to $_near! $_far");
|
print("Setting camera culling to $_near! $_far");
|
||||||
widget.controller.viewer.setCameraCulling(_near!, _far!);
|
widget.viewer.setCameraCulling(_near!, _far!);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
v.toStringAsFixed(2),
|
v.toStringAsFixed(2),
|
||||||
@@ -95,21 +95,21 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
child: const Text("Set far")),
|
child: const Text("Set far")),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
widget.controller.viewer.setCameraPosition(1.0, 1.0, -1.0);
|
widget.viewer.setCameraPosition(1.0, 1.0, -1.0);
|
||||||
},
|
},
|
||||||
child: const Text('Set position to 1, 1, -1 (leave rotation as-is)'),
|
child: const Text('Set position to 1, 1, -1 (leave rotation as-is)'),
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
widget.controller.viewer.setCameraPosition(0.0, 0.0, 0.0);
|
widget.viewer.setCameraPosition(0.0, 0.0, 0.0);
|
||||||
widget.controller.viewer.setCameraRotation(
|
widget.viewer.setCameraRotation(
|
||||||
v.Quaternion.axisAngle(v.Vector3(0, 0.0, 1.0), 0.0));
|
v.Quaternion.axisAngle(v.Vector3(0, 0.0, 1.0), 0.0));
|
||||||
},
|
},
|
||||||
child: const Text('Move to 0,0,0, facing towards 0,0,-1'),
|
child: const Text('Move to 0,0,0, facing towards 0,0,-1'),
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.setCameraRotation(
|
widget.viewer.setCameraRotation(
|
||||||
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), pi / 4));
|
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), pi / 4));
|
||||||
},
|
},
|
||||||
child: const Text("Rotate camera 45 degrees around y axis"),
|
child: const Text("Rotate camera 45 degrees around y axis"),
|
||||||
@@ -118,7 +118,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.frustumCulling =
|
ExampleWidgetState.frustumCulling =
|
||||||
!ExampleWidgetState.frustumCulling;
|
!ExampleWidgetState.frustumCulling;
|
||||||
widget.controller.viewer
|
widget.viewer
|
||||||
.setViewFrustumCulling(ExampleWidgetState.frustumCulling);
|
.setViewFrustumCulling(ExampleWidgetState.frustumCulling);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -128,7 +128,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
closeOnActivate: false,
|
closeOnActivate: false,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
var projMatrix =
|
var projMatrix =
|
||||||
await widget.controller.viewer.getCameraProjectionMatrix();
|
await widget.viewer.getCameraProjectionMatrix();
|
||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) {
|
builder: (ctx) {
|
||||||
@@ -147,7 +147,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
menuChildren: ManipulatorMode.values.map((mm) {
|
menuChildren: ManipulatorMode.values.map((mm) {
|
||||||
return MenuItemButton(
|
return MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.setCameraManipulatorOptions(
|
widget.viewer.setCameraManipulatorOptions(
|
||||||
mode: mm,
|
mode: mm,
|
||||||
orbitSpeedX: ExampleWidgetState.orbitSpeedX,
|
orbitSpeedX: ExampleWidgetState.orbitSpeedX,
|
||||||
orbitSpeedY: ExampleWidgetState.orbitSpeedY,
|
orbitSpeedY: ExampleWidgetState.orbitSpeedY,
|
||||||
@@ -169,7 +169,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
return MenuItemButton(
|
return MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.zoomSpeed = speed;
|
ExampleWidgetState.zoomSpeed = speed;
|
||||||
widget.controller.viewer.setCameraManipulatorOptions(
|
widget.viewer.setCameraManipulatorOptions(
|
||||||
orbitSpeedX: ExampleWidgetState.orbitSpeedX,
|
orbitSpeedX: ExampleWidgetState.orbitSpeedX,
|
||||||
orbitSpeedY: ExampleWidgetState.orbitSpeedY,
|
orbitSpeedY: ExampleWidgetState.orbitSpeedY,
|
||||||
zoomSpeed: ExampleWidgetState.zoomSpeed);
|
zoomSpeed: ExampleWidgetState.zoomSpeed);
|
||||||
@@ -191,7 +191,7 @@ class _CameraSubmenuState extends State<CameraSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.orbitSpeedX = speed;
|
ExampleWidgetState.orbitSpeedX = speed;
|
||||||
ExampleWidgetState.orbitSpeedY = speed;
|
ExampleWidgetState.orbitSpeedY = speed;
|
||||||
widget.controller.viewer.setCameraManipulatorOptions(
|
widget.viewer.setCameraManipulatorOptions(
|
||||||
orbitSpeedX: ExampleWidgetState.orbitSpeedX,
|
orbitSpeedX: ExampleWidgetState.orbitSpeedX,
|
||||||
orbitSpeedY: ExampleWidgetState.orbitSpeedY,
|
orbitSpeedY: ExampleWidgetState.orbitSpeedY,
|
||||||
zoomSpeed: ExampleWidgetState.zoomSpeed);
|
zoomSpeed: ExampleWidgetState.zoomSpeed);
|
||||||
|
|||||||
@@ -5,29 +5,31 @@ import 'package:flutter/widgets.dart';
|
|||||||
|
|
||||||
import 'package:thermion_flutter/thermion_flutter.dart';
|
import 'package:thermion_flutter/thermion_flutter.dart';
|
||||||
|
|
||||||
class ControllerMenu extends StatefulWidget {
|
class ViewerMenu extends StatefulWidget {
|
||||||
final ThermionFlutterPlugin controller;
|
final ThermionViewer? viewer;
|
||||||
final void Function() onToggleViewport;
|
final void Function() onToggleViewport;
|
||||||
final void Function() onControllerCreated;
|
final void Function(ThermionViewer viewer) onViewerCreated;
|
||||||
final void Function() onControllerDestroyed;
|
final void Function() onViewerDestroyed;
|
||||||
final FocusNode sharedFocusNode;
|
final FocusNode sharedFocusNode;
|
||||||
|
|
||||||
|
|
||||||
ControllerMenu(
|
ViewerMenu(
|
||||||
{required this.controller,
|
{
|
||||||
required this.onControllerCreated,
|
required this.viewer,
|
||||||
required this.onControllerDestroyed,
|
required this.onViewerCreated,
|
||||||
|
required this.onViewerDestroyed,
|
||||||
required this.sharedFocusNode,
|
required this.sharedFocusNode,
|
||||||
required this.onToggleViewport});
|
required this.onToggleViewport});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _ControllerMenuState();
|
State<StatefulWidget> createState() => _ViewerMenuState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ControllerMenuState extends State<ControllerMenu> {
|
class _ViewerMenuState extends State<ViewerMenu> {
|
||||||
void _createController({String? uberArchivePath}) async {
|
void _createViewer({String? uberArchivePath}) async {
|
||||||
widget.controller.initialize(uberArchivePath: uberArchivePath);
|
var viewer = await ThermionFlutterPlugin.createViewer(
|
||||||
widget.onControllerCreated();
|
uberArchivePath: uberArchivePath);
|
||||||
|
await viewer.initialized;
|
||||||
|
widget.onViewerCreated(viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -36,7 +38,7 @@ class _ControllerMenuState extends State<ControllerMenu> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(ControllerMenu oldWidget) {
|
void didUpdateWidget(ViewerMenu oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,14 +52,14 @@ class _ControllerMenuState extends State<ControllerMenu> {
|
|||||||
child:
|
child:
|
||||||
const Text("Create ThermionFlutterPlugin (default ubershader)"),
|
const Text("Create ThermionFlutterPlugin (default ubershader)"),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_createController();
|
_createViewer();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
child: const Text(
|
child: const Text(
|
||||||
"Create ThermionFlutterPlugin (custom ubershader - lit opaque only)"),
|
"Create ThermionFlutterPlugin (custom ubershader - lit opaque only)"),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_createController(
|
_createViewer(
|
||||||
uberArchivePath: Platform.isWindows
|
uberArchivePath: Platform.isWindows
|
||||||
? "assets/lit_opaque_32.uberz"
|
? "assets/lit_opaque_32.uberz"
|
||||||
: Platform.isMacOS
|
: Platform.isMacOS
|
||||||
@@ -73,8 +75,8 @@ class _ControllerMenuState extends State<ControllerMenu> {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
child: const Text("Destroy viewer"),
|
child: const Text("Destroy viewer"),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
widget.controller.dispose();
|
widget.viewer!.dispose();
|
||||||
widget.onControllerDestroyed();
|
widget.onViewerDestroyed();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -89,8 +91,7 @@ class _ControllerMenuState extends State<ControllerMenu> {
|
|||||||
onPressed: widget.onToggleViewport,
|
onPressed: widget.onToggleViewport,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
builder:
|
builder: (BuildContext context, MenuController controller, Widget? child) {
|
||||||
(BuildContext context, MenuController controller, Widget? child) {
|
|
||||||
return TextButton(
|
return TextButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (controller.isOpen) {
|
if (controller.isOpen) {
|
||||||
@@ -99,7 +100,7 @@ class _ControllerMenuState extends State<ControllerMenu> {
|
|||||||
controller.open();
|
controller.open();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: const Text("Controller / Viewer"),
|
child: const Text("Viewer / Viewer"),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import 'package:thermion_flutter_example/main.dart';
|
|||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
|
|
||||||
class RenderingSubmenu extends StatefulWidget {
|
class RenderingSubmenu extends StatefulWidget {
|
||||||
final ThermionFlutterPlugin controller;
|
final ThermionViewer viewer;
|
||||||
|
|
||||||
const RenderingSubmenu({super.key, required this.controller});
|
const RenderingSubmenu({super.key, required this.viewer});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _RenderingSubmenuState();
|
State<StatefulWidget> createState() => _RenderingSubmenuState();
|
||||||
@@ -19,14 +19,14 @@ class _RenderingSubmenuState extends State<RenderingSubmenu> {
|
|||||||
menuChildren: [
|
menuChildren: [
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.render();
|
widget.viewer.render();
|
||||||
},
|
},
|
||||||
child: const Text("Render single frame"),
|
child: const Text("Render single frame"),
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.rendering = !ExampleWidgetState.rendering;
|
ExampleWidgetState.rendering = !ExampleWidgetState.rendering;
|
||||||
widget.controller.viewer.setRendering(ExampleWidgetState.rendering);
|
widget.viewer.setRendering(ExampleWidgetState.rendering);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
"Set continuous rendering to ${!ExampleWidgetState.rendering}"),
|
"Set continuous rendering to ${!ExampleWidgetState.rendering}"),
|
||||||
@@ -35,14 +35,14 @@ class _RenderingSubmenuState extends State<RenderingSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.framerate =
|
ExampleWidgetState.framerate =
|
||||||
ExampleWidgetState.framerate == 60 ? 30 : 60;
|
ExampleWidgetState.framerate == 60 ? 30 : 60;
|
||||||
widget.controller.viewer.setFrameRate(ExampleWidgetState.framerate);
|
widget.viewer.setFrameRate(ExampleWidgetState.framerate);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
"Toggle framerate (currently ${ExampleWidgetState.framerate}) "),
|
"Toggle framerate (currently ${ExampleWidgetState.framerate}) "),
|
||||||
),
|
),
|
||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
widget.controller.viewer.setToneMapping(ToneMapper.LINEAR);
|
widget.viewer.setToneMapping(ToneMapper.LINEAR);
|
||||||
},
|
},
|
||||||
child: const Text("Set tone mapping to linear"),
|
child: const Text("Set tone mapping to linear"),
|
||||||
),
|
),
|
||||||
@@ -50,7 +50,7 @@ class _RenderingSubmenuState extends State<RenderingSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.postProcessing =
|
ExampleWidgetState.postProcessing =
|
||||||
!ExampleWidgetState.postProcessing;
|
!ExampleWidgetState.postProcessing;
|
||||||
widget.controller.viewer
|
widget.viewer
|
||||||
.setPostProcessing(ExampleWidgetState.postProcessing);
|
.setPostProcessing(ExampleWidgetState.postProcessing);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -60,7 +60,7 @@ class _RenderingSubmenuState extends State<RenderingSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.antiAliasingMsaa =
|
ExampleWidgetState.antiAliasingMsaa =
|
||||||
!ExampleWidgetState.antiAliasingMsaa;
|
!ExampleWidgetState.antiAliasingMsaa;
|
||||||
widget.controller.viewer.setAntiAliasing(
|
widget.viewer.setAntiAliasing(
|
||||||
ExampleWidgetState.antiAliasingMsaa,
|
ExampleWidgetState.antiAliasingMsaa,
|
||||||
ExampleWidgetState.antiAliasingFxaa,
|
ExampleWidgetState.antiAliasingFxaa,
|
||||||
ExampleWidgetState.antiAliasingTaa);
|
ExampleWidgetState.antiAliasingTaa);
|
||||||
@@ -72,7 +72,7 @@ class _RenderingSubmenuState extends State<RenderingSubmenu> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.antiAliasingFxaa =
|
ExampleWidgetState.antiAliasingFxaa =
|
||||||
!ExampleWidgetState.antiAliasingFxaa;
|
!ExampleWidgetState.antiAliasingFxaa;
|
||||||
widget.controller.viewer.setAntiAliasing(
|
widget.viewer.setAntiAliasing(
|
||||||
ExampleWidgetState.antiAliasingMsaa,
|
ExampleWidgetState.antiAliasingMsaa,
|
||||||
ExampleWidgetState.antiAliasingFxaa,
|
ExampleWidgetState.antiAliasingFxaa,
|
||||||
ExampleWidgetState.antiAliasingTaa);
|
ExampleWidgetState.antiAliasingTaa);
|
||||||
@@ -83,7 +83,7 @@ class _RenderingSubmenuState extends State<RenderingSubmenu> {
|
|||||||
MenuItemButton(
|
MenuItemButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
ExampleWidgetState.recording = !ExampleWidgetState.recording;
|
ExampleWidgetState.recording = !ExampleWidgetState.recording;
|
||||||
widget.controller.viewer.setRecording(ExampleWidgetState.recording);
|
widget.viewer.setRecording(ExampleWidgetState.recording);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
"Turn recording ${ExampleWidgetState.recording ? "OFF" : "ON"}) "),
|
"Turn recording ${ExampleWidgetState.recording ? "OFF" : "ON"}) "),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import 'package:thermion_flutter_example/menus/camera_submenu.dart';
|
|||||||
import 'package:thermion_flutter_example/menus/rendering_submenu.dart';
|
import 'package:thermion_flutter_example/menus/rendering_submenu.dart';
|
||||||
|
|
||||||
class SceneMenu extends StatefulWidget {
|
class SceneMenu extends StatefulWidget {
|
||||||
final ThermionFlutterPlugin? controller;
|
final ThermionViewer? controller;
|
||||||
final FocusNode sharedFocusNode;
|
final FocusNode sharedFocusNode;
|
||||||
|
|
||||||
const SceneMenu(
|
const SceneMenu(
|
||||||
@@ -37,11 +37,11 @@ class _SceneMenuState extends State<SceneMenu> {
|
|||||||
? []
|
? []
|
||||||
: <Widget>[
|
: <Widget>[
|
||||||
RenderingSubmenu(
|
RenderingSubmenu(
|
||||||
controller: widget.controller!,
|
viewer: widget.controller!,
|
||||||
),
|
),
|
||||||
AssetSubmenu(controller: widget.controller!),
|
AssetSubmenu(viewer: widget.controller!),
|
||||||
CameraSubmenu(
|
CameraSubmenu(
|
||||||
controller: widget.controller!,
|
viewer: widget.controller!,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
builder:
|
builder:
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
PODS:
|
|
||||||
- FlutterMacOS (1.0.0)
|
|
||||||
- path_provider_foundation (0.0.1):
|
|
||||||
- Flutter
|
|
||||||
- FlutterMacOS
|
|
||||||
- thermion_flutter (0.0.1):
|
|
||||||
- FlutterMacOS
|
|
||||||
|
|
||||||
DEPENDENCIES:
|
|
||||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
|
||||||
- path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`)
|
|
||||||
- thermion_flutter (from `Flutter/ephemeral/.symlinks/plugins/thermion_flutter/macos`)
|
|
||||||
|
|
||||||
EXTERNAL SOURCES:
|
|
||||||
FlutterMacOS:
|
|
||||||
:path: Flutter/ephemeral
|
|
||||||
path_provider_foundation:
|
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin
|
|
||||||
thermion_flutter:
|
|
||||||
:path: Flutter/ephemeral/.symlinks/plugins/thermion_flutter/macos
|
|
||||||
|
|
||||||
SPEC CHECKSUMS:
|
|
||||||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
|
||||||
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
|
|
||||||
thermion_flutter: e4895ade6b14d9efb6e17ed2436e89dbb87fa998
|
|
||||||
|
|
||||||
PODFILE CHECKSUM: 1888651be91a8ad58692c1add9ce24279fd4e950
|
|
||||||
|
|
||||||
COCOAPODS: 1.15.2
|
|
||||||
@@ -17,6 +17,18 @@ dependencies:
|
|||||||
cupertino_icons: ^1.0.2
|
cupertino_icons: ^1.0.2
|
||||||
web:
|
web:
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
thermion_flutter:
|
||||||
|
path: ../../../thermion_flutter/thermion_flutter
|
||||||
|
thermion_flutter_platform_interface:
|
||||||
|
path: ../../../thermion_flutter/thermion_flutter_platform_interface
|
||||||
|
thermion_flutter_ffi:
|
||||||
|
path: ../../../thermion_flutter/thermion_flutter_ffi
|
||||||
|
thermion_flutter_web:
|
||||||
|
path: ../../../thermion_flutter/thermion_flutter_web
|
||||||
|
thermion_dart:
|
||||||
|
path: ../../../thermion_dart
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
@@ -36,4 +48,4 @@ flutter:
|
|||||||
- assets/BusterDrone/
|
- assets/BusterDrone/
|
||||||
- assets/BusterDrone/textures/
|
- assets/BusterDrone/textures/
|
||||||
- assets/FlightHelmet/
|
- assets/FlightHelmet/
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
# platform :ios, '12.0'
|
platform :ios, '13.0'
|
||||||
|
|
||||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||||
|
|||||||
22
examples/flutter/quickstart/ios/Podfile.lock
Normal file
22
examples/flutter/quickstart/ios/Podfile.lock
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
PODS:
|
||||||
|
- Flutter (1.0.0)
|
||||||
|
- thermion_flutter (0.0.1):
|
||||||
|
- Flutter
|
||||||
|
|
||||||
|
DEPENDENCIES:
|
||||||
|
- Flutter (from `Flutter`)
|
||||||
|
- thermion_flutter (from `.symlinks/plugins/thermion_flutter/ios`)
|
||||||
|
|
||||||
|
EXTERNAL SOURCES:
|
||||||
|
Flutter:
|
||||||
|
:path: Flutter
|
||||||
|
thermion_flutter:
|
||||||
|
:path: ".symlinks/plugins/thermion_flutter/ios"
|
||||||
|
|
||||||
|
SPEC CHECKSUMS:
|
||||||
|
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||||
|
thermion_flutter: c965e09831858465a1a8df59ff97e40a4d002773
|
||||||
|
|
||||||
|
PODFILE CHECKSUM: a57f30d18f102dd3ce366b1d62a55ecbef2158e5
|
||||||
|
|
||||||
|
COCOAPODS: 1.15.2
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||||
|
F657CCCFB062AF56C7F1E15C /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D988E66CA93AB1163F3B4F2 /* Pods_RunnerTests.framework */; };
|
||||||
|
F8DC37C0013EE3DC8802435E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B0831D015898C7047513698C /* Pods_Runner.framework */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -42,12 +44,17 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||||
|
31D54E0731320192F7631461 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
3680A9DFE5EC3E59C051B544 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||||
|
3D988E66CA93AB1163F3B4F2 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
704E1C99CAABFB056933D88F /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||||
|
8C0FE5C77038897D844C5D42 /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@@ -55,6 +62,9 @@
|
|||||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
|
9CD72080C199DAE3518D4C3D /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||||
|
B0831D015898C7047513698C /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
BA68F2C1572D8BC92CC4C4FF /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -62,12 +72,30 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
F8DC37C0013EE3DC8802435E /* Pods_Runner.framework in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
|
FA72758808529BDB8770545F /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
F657CCCFB062AF56C7F1E15C /* Pods_RunnerTests.framework in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
0DB20859A61D425430A5D097 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
B0831D015898C7047513698C /* Pods_Runner.framework */,
|
||||||
|
3D988E66CA93AB1163F3B4F2 /* Pods_RunnerTests.framework */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -76,6 +104,20 @@
|
|||||||
path = RunnerTests;
|
path = RunnerTests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
4A129A4D3EB41F9DE0778AAC /* Pods */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
704E1C99CAABFB056933D88F /* Pods-Runner.debug.xcconfig */,
|
||||||
|
3680A9DFE5EC3E59C051B544 /* Pods-Runner.release.xcconfig */,
|
||||||
|
8C0FE5C77038897D844C5D42 /* Pods-Runner.profile.xcconfig */,
|
||||||
|
31D54E0731320192F7631461 /* Pods-RunnerTests.debug.xcconfig */,
|
||||||
|
BA68F2C1572D8BC92CC4C4FF /* Pods-RunnerTests.release.xcconfig */,
|
||||||
|
9CD72080C199DAE3518D4C3D /* Pods-RunnerTests.profile.xcconfig */,
|
||||||
|
);
|
||||||
|
name = Pods;
|
||||||
|
path = Pods;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -94,6 +136,8 @@
|
|||||||
97C146F01CF9000F007C117D /* Runner */,
|
97C146F01CF9000F007C117D /* Runner */,
|
||||||
97C146EF1CF9000F007C117D /* Products */,
|
97C146EF1CF9000F007C117D /* Products */,
|
||||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||||
|
4A129A4D3EB41F9DE0778AAC /* Pods */,
|
||||||
|
0DB20859A61D425430A5D097 /* Frameworks */,
|
||||||
);
|
);
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
@@ -128,8 +172,10 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
78F05AF37D9E628BE6E89ABD /* [CP] Check Pods Manifest.lock */,
|
||||||
331C807D294A63A400263BE5 /* Sources */,
|
331C807D294A63A400263BE5 /* Sources */,
|
||||||
331C807F294A63A400263BE5 /* Resources */,
|
331C807F294A63A400263BE5 /* Resources */,
|
||||||
|
FA72758808529BDB8770545F /* Frameworks */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -145,6 +191,7 @@
|
|||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||||
buildPhases = (
|
buildPhases = (
|
||||||
|
C7C2718364AC4E2451407065 /* [CP] Check Pods Manifest.lock */,
|
||||||
9740EEB61CF901F6004384FC /* Run Script */,
|
9740EEB61CF901F6004384FC /* Run Script */,
|
||||||
97C146EA1CF9000F007C117D /* Sources */,
|
97C146EA1CF9000F007C117D /* Sources */,
|
||||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||||
@@ -238,6 +285,28 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||||
};
|
};
|
||||||
|
78F05AF37D9E628BE6E89ABD /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
alwaysOutOfDate = 1;
|
alwaysOutOfDate = 1;
|
||||||
@@ -253,6 +322,28 @@
|
|||||||
shellPath = /bin/sh;
|
shellPath = /bin/sh;
|
||||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||||
};
|
};
|
||||||
|
C7C2718364AC4E2451407065 /* [CP] Check Pods Manifest.lock */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
|
||||||
|
"${PODS_ROOT}/Manifest.lock",
|
||||||
|
);
|
||||||
|
name = "[CP] Check Pods Manifest.lock";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||||
|
showEnvVarsInLog = 0;
|
||||||
|
};
|
||||||
/* End PBXShellScriptBuildPhase section */
|
/* End PBXShellScriptBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -365,6 +456,7 @@
|
|||||||
DEVELOPMENT_TEAM = TM2B4SJXNJ;
|
DEVELOPMENT_TEAM = TM2B4SJXNJ;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -379,6 +471,7 @@
|
|||||||
};
|
};
|
||||||
331C8088294A63A400263BE5 /* Debug */ = {
|
331C8088294A63A400263BE5 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 31D54E0731320192F7631461 /* Pods-RunnerTests.debug.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -396,6 +489,7 @@
|
|||||||
};
|
};
|
||||||
331C8089294A63A400263BE5 /* Release */ = {
|
331C8089294A63A400263BE5 /* Release */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = BA68F2C1572D8BC92CC4C4FF /* Pods-RunnerTests.release.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -411,6 +505,7 @@
|
|||||||
};
|
};
|
||||||
331C808A294A63A400263BE5 /* Profile */ = {
|
331C808A294A63A400263BE5 /* Profile */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
|
baseConfigurationReference = 9CD72080C199DAE3518D4C3D /* Pods-RunnerTests.profile.xcconfig */;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
@@ -545,6 +640,7 @@
|
|||||||
DEVELOPMENT_TEAM = TM2B4SJXNJ;
|
DEVELOPMENT_TEAM = TM2B4SJXNJ;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
@@ -568,6 +664,7 @@
|
|||||||
DEVELOPMENT_TEAM = TM2B4SJXNJ;
|
DEVELOPMENT_TEAM = TM2B4SJXNJ;
|
||||||
ENABLE_BITCODE = NO;
|
ENABLE_BITCODE = NO;
|
||||||
INFOPLIST_FILE = Runner/Info.plist;
|
INFOPLIST_FILE = Runner/Info.plist;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
|
|||||||
@@ -4,4 +4,7 @@
|
|||||||
<FileRef
|
<FileRef
|
||||||
location = "group:Runner.xcodeproj">
|
location = "group:Runner.xcodeproj">
|
||||||
</FileRef>
|
</FileRef>
|
||||||
|
<FileRef
|
||||||
|
location = "group:Pods/Pods.xcodeproj">
|
||||||
|
</FileRef>
|
||||||
</Workspace>
|
</Workspace>
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import 'package:thermion_flutter/thermion_flutter.dart';
|
|||||||
import 'package:vector_math/vector_math_64.dart' as v;
|
import 'package:vector_math/vector_math_64.dart' as v;
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
}
|
}
|
||||||
@@ -35,40 +34,59 @@ class MyHomePage extends StatefulWidget {
|
|||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
bool _loaded = false;
|
bool _loaded = false;
|
||||||
late ThermionFlutterPlugin _thermionFlutterPlugin;
|
ThermionViewer? _thermionViewer;
|
||||||
late Future<ThermionViewer> _thermionViewer;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_thermionFlutterPlugin = ThermionFlutterPlugin();
|
}
|
||||||
_thermionViewer = _thermionFlutterPlugin.initialize();
|
|
||||||
|
ThermionFlutterTexture? _texture;
|
||||||
|
|
||||||
|
Future _load() async {
|
||||||
|
var viewer = await ThermionFlutterPlugin.createViewer();
|
||||||
|
_thermionViewer = viewer;
|
||||||
|
_thermionViewer!.loadSkybox("assets/default_env_skybox.ktx");
|
||||||
|
_thermionViewer!.loadGlb("assets/cube.glb");
|
||||||
|
|
||||||
|
_thermionViewer!.setCameraPosition(0, 1, 10);
|
||||||
|
_thermionViewer!.setCameraRotation(
|
||||||
|
v.Quaternion.axisAngle(v.Vector3(1, 0, 0), -30 / 180 * pi) *
|
||||||
|
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), 15 / 180 * pi));
|
||||||
|
_thermionViewer!.addLight(LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
|
||||||
|
_thermionViewer!.setRendering(true);
|
||||||
|
_loaded = true;
|
||||||
|
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _unload() async {
|
||||||
|
await ThermionFlutterPlugin.destroyTexture(_texture!);
|
||||||
|
var viewer = _thermionViewer!;
|
||||||
|
_thermionViewer = null;
|
||||||
|
setState(() {});
|
||||||
|
await viewer.dispose();
|
||||||
|
_loaded = false;
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _loadButton() {
|
||||||
|
return Center(
|
||||||
|
child: ElevatedButton(child: const Text("Load"), onPressed: _load));
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _unloadButton() {
|
||||||
|
return Center(
|
||||||
|
child: ElevatedButton(child: const Text("Unload"), onPressed: _unload));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(children: [
|
return Stack(children: [
|
||||||
Positioned.fill(child: ThermionWidget(plugin: _thermionFlutterPlugin)),
|
if (_thermionViewer != null)
|
||||||
if (!_loaded)
|
Positioned.fill(child: ThermionWidget(viewer: _thermionViewer!)),
|
||||||
Center(
|
if (!_loaded) _loadButton(),
|
||||||
child: ElevatedButton(
|
if (_loaded) _unloadButton(),
|
||||||
child: const Text("Load"),
|
|
||||||
onPressed: () async {
|
|
||||||
var viewer = await _thermionViewer;
|
|
||||||
await viewer.loadSkybox("assets/default_env_skybox.ktx");
|
|
||||||
await viewer.loadGlb("assets/cube.glb");
|
|
||||||
|
|
||||||
await viewer.setCameraPosition(0, 1, 10);
|
|
||||||
await viewer.setCameraRotation(v.Quaternion.axisAngle(
|
|
||||||
v.Vector3(1, 0, 0), -30 / 180 * pi) *
|
|
||||||
v.Quaternion.axisAngle(
|
|
||||||
v.Vector3(0, 1, 0), 15 / 180 * pi));
|
|
||||||
await viewer.addLight(
|
|
||||||
LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
|
|
||||||
await viewer.setRendering(true);
|
|
||||||
_loaded = true;
|
|
||||||
setState(() {});
|
|
||||||
}))
|
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
|||||||
version: 1.0.0+1
|
version: 1.0.0+1
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: '>=3.5.0-250.0.dev <4.0.0'
|
sdk: '>=3.3.0 <4.0.0'
|
||||||
|
|
||||||
# Dependencies specify other packages that your package needs in order to work.
|
# Dependencies specify other packages that your package needs in order to work.
|
||||||
# To automatically upgrade your package dependencies to the latest versions
|
# To automatically upgrade your package dependencies to the latest versions
|
||||||
@@ -30,11 +30,7 @@ environment:
|
|||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
thermion_flutter:
|
thermion_flutter:
|
||||||
path: ../../../thermion_flutter/thermion_flutter
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
|
||||||
cupertino_icons: ^1.0.8
|
cupertino_icons: ^1.0.8
|
||||||
vector_math: ^2.1.4
|
vector_math: ^2.1.4
|
||||||
|
|
||||||
|
|||||||
4
melos.yaml
Normal file
4
melos.yaml
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
name: thermion_workspace
|
||||||
|
packages:
|
||||||
|
- thermion_dart
|
||||||
|
- thermion_flutter/**
|
||||||
6
pubspec.yaml
Normal file
6
pubspec.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
name: thermion_workspace
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: '>=3.0.0 <4.0.0'
|
||||||
|
dev_dependencies:
|
||||||
|
melos: ^6.1.0
|
||||||
@@ -1,2 +1,36 @@
|
|||||||
|
## 0.1.1+2
|
||||||
|
|
||||||
|
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
|
||||||
|
|
||||||
|
## 0.1.1-dev.0+2
|
||||||
|
|
||||||
|
- **FIX**: revert to std::thread (pthreads not easily available on Windows).
|
||||||
|
- **FIX**: on Windows, pass static libs via -l rather than custom linkWith property so build.dart stays compatible between published & custom versions.
|
||||||
|
|
||||||
|
## 0.1.1+1
|
||||||
|
|
||||||
|
- **DOCS**: update with links to playground.
|
||||||
|
|
||||||
|
## 0.1.1
|
||||||
|
|
||||||
|
- Bump "thermion_dart" to `0.1.1`.
|
||||||
|
|
||||||
|
## 0.1.0+4
|
||||||
|
|
||||||
|
- **FIX**: add dummy asset to build.dart on Linux builds so we can use the package on a Linux host.
|
||||||
|
|
||||||
|
## 0.1.0+3
|
||||||
|
|
||||||
|
- **FIX**: exit build.dart early on Linux builds so we can use the package on a Linux host.
|
||||||
|
|
||||||
|
## 0.1.0+2
|
||||||
|
|
||||||
|
- **REFACTOR**: rearrange some stubs/imports for easier web WASM deployment.
|
||||||
|
|
||||||
|
## 0.1.0+1
|
||||||
|
|
||||||
|
- **REFACTOR**: export ThermionViewerWasm for web and hide FFI/WASM version.
|
||||||
|
- **FIX**: use preserveDrawingBuffer=true on web.
|
||||||
|
|
||||||
## 0.0.1
|
## 0.0.1
|
||||||
* First release of Dart-only package
|
* First release of Dart-only package
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
<a href="https://docs.page/nmfisher/flutter_filament/quickstart">Quickstart (Flutter)</a> •
|
<a href="https://docs.page/nmfisher/flutter_filament/quickstart">Quickstart (Flutter)</a> •
|
||||||
<a href="https://docs.page/nmfisher/flutter_filament">Documentation</a> •
|
<a href="https://docs.page/nmfisher/flutter_filament">Documentation</a> •
|
||||||
<a href="https://github.com/nmfisher/thermion/docs/examples/">Showcase</a> •
|
<a href="https://github.com/nmfisher/thermion/docs/examples/">Showcase</a> •
|
||||||
|
<a href="https://dartpad.thermion.dev/">Playground</a> •
|
||||||
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,48 @@ import 'package:native_toolchain_c/native_toolchain_c.dart';
|
|||||||
|
|
||||||
void main(List<String> args) async {
|
void main(List<String> args) async {
|
||||||
await build(args, (config, output) async {
|
await build(args, (config, output) async {
|
||||||
|
var logDir = Directory(
|
||||||
|
"${config.packageRoot.toFilePath()}.dart_tool/thermion_dart/log/");
|
||||||
|
if (!logDir.existsSync()) {
|
||||||
|
logDir.createSync(recursive: true);
|
||||||
|
}
|
||||||
|
var logFile = File(logDir.path + "/build.log");
|
||||||
|
|
||||||
final logger = Logger("")..level = Level.ALL
|
final logger = Logger("")
|
||||||
..onRecord.listen((record) => print(record.message));
|
..level = Level.ALL
|
||||||
|
..onRecord.listen((record) => logFile.writeAsStringSync(
|
||||||
|
record.message + "\n",
|
||||||
|
mode: FileMode.append,
|
||||||
|
flush: true));
|
||||||
|
|
||||||
var platform = config.targetOS.toString().toLowerCase();
|
var platform = config.targetOS.toString().toLowerCase();
|
||||||
|
|
||||||
|
// We don't support Linux (yet), so the native/Filament libraries won't be
|
||||||
|
// compiled/available. However, we still want to be able to run the Dart
|
||||||
|
// package itself on a Linux host(e.g. for dart_services backed), so if
|
||||||
|
// we detect that we're running on Linux, add some dummy native code
|
||||||
|
// assets and exit early.
|
||||||
|
if (platform == "linux") {
|
||||||
|
final linkMode = DynamicLoadingBundled();
|
||||||
|
final name = "thermion_dart.dart";
|
||||||
|
final libUri = config.outputDirectory
|
||||||
|
.resolve(config.targetOS.libraryFileName(name, linkMode));
|
||||||
|
output.addAssets(
|
||||||
|
[
|
||||||
|
NativeCodeAsset(
|
||||||
|
package: config.packageName,
|
||||||
|
name: name,
|
||||||
|
file: libUri,
|
||||||
|
linkMode: linkMode,
|
||||||
|
os: config.targetOS,
|
||||||
|
architecture: config.dryRun ? null : config.targetArchitecture,
|
||||||
|
)
|
||||||
|
],
|
||||||
|
linkInPackage: null,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var libDir = config.dryRun ? "" : (await getLibDir(config, logger)).path;
|
var libDir = config.dryRun ? "" : (await getLibDir(config, logger)).path;
|
||||||
|
|
||||||
final packageName = config.packageName;
|
final packageName = config.packageName;
|
||||||
@@ -26,7 +62,7 @@ void main(List<String> args) async {
|
|||||||
"${config.packageRoot.toFilePath()}/native/include/material/image.c",
|
"${config.packageRoot.toFilePath()}/native/include/material/image.c",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final libs = [
|
var libs = [
|
||||||
"filament",
|
"filament",
|
||||||
"backend",
|
"backend",
|
||||||
"filameshio",
|
"filameshio",
|
||||||
@@ -55,12 +91,12 @@ void main(List<String> args) async {
|
|||||||
"basis_transcoder"
|
"basis_transcoder"
|
||||||
];
|
];
|
||||||
|
|
||||||
final linkWith = <String>[];
|
|
||||||
|
|
||||||
if (platform == "windows") {
|
if (platform == "windows") {
|
||||||
linkWith.addAll(libs.map((lib) => "$libDir/$lib.lib"));
|
libDir = Directory(libDir).uri.toFilePath();
|
||||||
linkWith.addAll(["$libDir/bluevk.lib", "$libDir/bluegl.lib"]);
|
libs = libs.map((lib) => "${libDir}${lib}.lib").toList();
|
||||||
linkWith.addAll([
|
libs.addAll(["${libDir}bluevk.lib", "${libDir}bluegl.lib"]);
|
||||||
|
libs.addAll([
|
||||||
"gdi32.lib",
|
"gdi32.lib",
|
||||||
"user32.lib",
|
"user32.lib",
|
||||||
"shell32.lib",
|
"shell32.lib",
|
||||||
@@ -71,7 +107,7 @@ void main(List<String> args) async {
|
|||||||
} else {
|
} else {
|
||||||
libs.add("stdc++");
|
libs.add("stdc++");
|
||||||
}
|
}
|
||||||
final flags = [];
|
final flags = []; //"-fsanitize=address"];
|
||||||
final defines = <String, String?>{};
|
final defines = <String, String?>{};
|
||||||
var frameworks = [];
|
var frameworks = [];
|
||||||
|
|
||||||
@@ -85,7 +121,15 @@ void main(List<String> args) async {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (platform == "ios") {
|
if (platform == "ios") {
|
||||||
frameworks.addAll(['Foundation', 'CoreGraphics', 'QuartzCore', 'GLKit', "Metal", 'CoreVideo', 'OpenGLES']);
|
frameworks.addAll([
|
||||||
|
'Foundation',
|
||||||
|
'CoreGraphics',
|
||||||
|
'QuartzCore',
|
||||||
|
'GLKit',
|
||||||
|
"Metal",
|
||||||
|
'CoreVideo',
|
||||||
|
'OpenGLES'
|
||||||
|
]);
|
||||||
} else if (platform == "macos") {
|
} else if (platform == "macos") {
|
||||||
frameworks.addAll([
|
frameworks.addAll([
|
||||||
'Foundation',
|
'Foundation',
|
||||||
@@ -107,14 +151,12 @@ void main(List<String> args) async {
|
|||||||
sources: sources,
|
sources: sources,
|
||||||
includes: ['native/include', 'native/include/filament'],
|
includes: ['native/include', 'native/include/filament'],
|
||||||
defines: defines,
|
defines: defines,
|
||||||
// UNCOMMENT THIS IF YOU ARE BUILDING WITH THE CUSTOM native_toolchain_c FORK FOR WINDOWS
|
|
||||||
// linkWith: linkWith,
|
|
||||||
flags: [
|
flags: [
|
||||||
if (platform == "macos") '-mmacosx-version-min=13.0',
|
if (platform == "macos") '-mmacosx-version-min=13.0',
|
||||||
if (platform == "ios") '-mios-version-min=13.0',
|
if (platform == "ios") '-mios-version-min=13.0',
|
||||||
...flags,
|
...flags,
|
||||||
...frameworks,
|
...frameworks,
|
||||||
if (platform != "windows") ...libs.map((lib) => "-l$lib"),
|
...libs.map((lib) => "-l$lib"),
|
||||||
"-L$libDir",
|
"-L$libDir",
|
||||||
],
|
],
|
||||||
dartBuildFiles: ['hook/build.dart'],
|
dartBuildFiles: ['hook/build.dart'],
|
||||||
@@ -162,87 +204,90 @@ void main(List<String> args) async {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
String _FILAMENT_VERSION ="v1.51.2";
|
String _FILAMENT_VERSION = "v1.51.2";
|
||||||
String _getLibraryUrl(String platform, String mode) {
|
String _getLibraryUrl(String platform, String mode) {
|
||||||
return "https://pub-c8b6266320924116aaddce03b5313c0a.r2.dev/filament-${_FILAMENT_VERSION}-${platform}-${mode}.zip";
|
return "https://pub-c8b6266320924116aaddce03b5313c0a.r2.dev/filament-${_FILAMENT_VERSION}-${platform}-${mode}.zip";
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Download precompiled Filament libraries for the target platform from Cloudflare.
|
// Download precompiled Filament libraries for the target platform from Cloudflare.
|
||||||
//
|
//
|
||||||
Future<Directory> getLibDir(BuildConfig config, Logger logger) async {
|
Future<Directory> getLibDir(BuildConfig config, Logger logger) async {
|
||||||
|
var platform = config.targetOS.toString().toLowerCase();
|
||||||
|
|
||||||
var platform = config.targetOS.toString().toLowerCase();
|
// Except on Windows, most users will only need release builds of Filament.
|
||||||
|
// Debug builds are probably only relevant if you're a package developer debugging an internal Filament issue
|
||||||
// Except on Windows, most users will only need release builds of Filament.
|
// or if you're working on Flutter+Windows (which requires the CRT debug DLLs).
|
||||||
// Debug builds are probably only relevant if you're a package developer debugging an internal Filament issue
|
// Also note that there are known driver issues with Android debug builds, e.g.:
|
||||||
// or if you're working on Flutter+Windows (which requires the CRT debug DLLs).
|
// https://github.com/google/filament/issues/7162
|
||||||
// Also note that there are known driver issues with Android debug builds, e.g.:
|
// (these aren't present in Filament release builds).
|
||||||
// https://github.com/google/filament/issues/7162
|
// However, if you know what you're doing, you can change "release" to "debug" below.
|
||||||
// (these aren't present in Filament release builds).
|
// TODO - check if we can pass this as a CLI compiler flag
|
||||||
// However, if you know what you're doing, you can change "release" to "debug" below.
|
var mode = "release";
|
||||||
// TODO - check if we can pass this as a CLI compiler flag
|
if (platform == "windows") {
|
||||||
var mode = "release";
|
mode = config.buildMode == BuildMode.debug ? "debug" : "release";
|
||||||
if(platform == "windows") {
|
}
|
||||||
mode = config.buildMode == BuildMode.debug ? "debug" : "release";
|
|
||||||
}
|
|
||||||
|
|
||||||
var libDir = Directory("${config.packageRoot.toFilePath()}/.dart_tool/thermion_dart/lib/${_FILAMENT_VERSION}/$platform/$mode/");
|
var libDir = Directory(
|
||||||
|
"${config.packageRoot.toFilePath()}/.dart_tool/thermion_dart/lib/${_FILAMENT_VERSION}/$platform/$mode/");
|
||||||
|
|
||||||
if (platform == "android") {
|
if (platform == "android") {
|
||||||
final archExtension = switch (config.targetArchitecture) {
|
final archExtension = switch (config.targetArchitecture) {
|
||||||
Architecture.arm => "armeabi-v7a",
|
Architecture.arm => "armeabi-v7a",
|
||||||
Architecture.arm64 => "arm64-v8a",
|
Architecture.arm64 => "arm64-v8a",
|
||||||
Architecture.x64 => "x86_64",
|
Architecture.x64 => "x86_64",
|
||||||
Architecture.ia32 => "x86",
|
Architecture.ia32 => "x86",
|
||||||
_ => throw FormatException('Invalid')
|
_ => throw FormatException('Invalid')
|
||||||
};
|
};
|
||||||
libDir = Directory("${libDir.path}/$archExtension/");
|
libDir = Directory("${libDir.path}/$archExtension/");
|
||||||
} else if(platform == "windows") {
|
} else if (platform == "windows") {
|
||||||
if(config.targetArchitecture != Architecture.x64) {
|
if (config.targetArchitecture != Architecture.x64) {
|
||||||
throw Exception("Unsupported architecture : ${config.targetArchitecture}");
|
throw Exception(
|
||||||
|
"Unsupported architecture : ${config.targetArchitecture}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final url = _getLibraryUrl(platform, mode);
|
||||||
|
|
||||||
|
final filename = url.split("/").last;
|
||||||
|
|
||||||
|
// We will write an empty file called success to the unzip directory after successfully downloading/extracting the prebuilt libraries.
|
||||||
|
// If this file already exists, we assume everything has been successfully extracted and skip
|
||||||
|
final unzipDir = platform == "android" ? libDir.parent.path : libDir.path;
|
||||||
|
final successToken = File("$unzipDir/success");
|
||||||
|
final libraryZip = File("$unzipDir/$filename");
|
||||||
|
|
||||||
|
if (!successToken.existsSync()) {
|
||||||
|
if (libraryZip.existsSync()) {
|
||||||
|
libraryZip.deleteSync();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!libraryZip.parent.existsSync()) {
|
||||||
|
libraryZip.parent.createSync(recursive: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
"Downloading prebuilt libraries for $platform/$mode from $url to ${libraryZip}, files will be unzipped to ${unzipDir}");
|
||||||
|
final request = await HttpClient().getUrl(Uri.parse(url));
|
||||||
|
final response = await request.close();
|
||||||
|
|
||||||
|
await response.pipe(libraryZip.openWrite());
|
||||||
|
|
||||||
|
final archive = ZipDecoder().decodeBytes(await libraryZip.readAsBytes());
|
||||||
|
|
||||||
|
for (final file in archive) {
|
||||||
|
final filename = file.name;
|
||||||
|
if (file.isFile) {
|
||||||
|
final data = file.content as List<int>;
|
||||||
|
final f = File('${unzipDir}/$filename');
|
||||||
|
await f.create(recursive: true);
|
||||||
|
await f.writeAsBytes(data);
|
||||||
|
} else {
|
||||||
|
final d = Directory('${unzipDir}/$filename');
|
||||||
|
await d.create(recursive: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
successToken.writeAsStringSync("SUCCESS");
|
||||||
final url = _getLibraryUrl(platform, mode);
|
}
|
||||||
|
return libDir;
|
||||||
final filename = url.split("/").last;
|
|
||||||
|
|
||||||
// Assume that the libraries exist if the directory containing them exists.
|
|
||||||
if (!libDir.existsSync()) {
|
|
||||||
|
|
||||||
final unzipDir = platform == "android" ? libDir.parent.path : libDir.path;
|
|
||||||
|
|
||||||
final libraryZip = File("$unzipDir/$filename");
|
|
||||||
|
|
||||||
if(libraryZip.existsSync()) {
|
|
||||||
libraryZip.deleteSync();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!libraryZip.parent.existsSync()) {
|
|
||||||
libraryZip.parent.createSync(recursive: true);
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Downloading prebuilt libraries for $platform/$mode from $url to ${libraryZip}, files will be unzipped to ${unzipDir}");
|
|
||||||
final request = await HttpClient().getUrl(Uri.parse(url));
|
|
||||||
final response = await request.close();
|
|
||||||
|
|
||||||
await response.pipe(libraryZip.openWrite());
|
|
||||||
|
|
||||||
final archive = ZipDecoder().decodeBytes(await libraryZip.readAsBytes());
|
|
||||||
|
|
||||||
for (final file in archive) {
|
|
||||||
final filename = file.name;
|
|
||||||
if (file.isFile) {
|
|
||||||
final data = file.content as List<int>;
|
|
||||||
final f = File('${unzipDir}/$filename');
|
|
||||||
await f.create(recursive: true);
|
|
||||||
await f.writeAsBytes(data);
|
|
||||||
} else {
|
|
||||||
final d = Directory('${unzipDir}/$filename');
|
|
||||||
await d.create(recursive: true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return libDir;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
library filament_dart;
|
library filament_dart;
|
||||||
|
|
||||||
export 'thermion_dart/thermion_viewer.dart';
|
export 'thermion_dart/thermion_viewer.dart';
|
||||||
export 'thermion_dart/thermion_viewer_ffi.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/entities/entity_transform_controller.dart';
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
export 'web/compatibility.dart' if (dart.library.io) 'native/compatibility.dart';
|
export 'native/compatibility.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import 'dart:convert';
|
|||||||
import 'dart:ffi' as ffi hide Uint8Pointer, FloatPointer;
|
import 'dart:ffi' as ffi hide Uint8Pointer, FloatPointer;
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/web/thermion_dart.g.dart';
|
import 'package:thermion_dart/thermion_dart/compatibility/web/ffi/thermion_dart.g.dart';
|
||||||
|
|
||||||
import 'package:ffi/ffi.dart';
|
import 'package:ffi/ffi.dart';
|
||||||
export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer;
|
export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:js_interop';
|
import 'dart:js_interop';
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/web/interop.dart';
|
import 'package:thermion_dart/thermion_dart/compatibility/web/ffi/interop.dart';
|
||||||
|
|
||||||
import "allocator.dart";
|
import "allocator.dart";
|
||||||
|
|
||||||
@@ -1,403 +0,0 @@
|
|||||||
@JS()
|
|
||||||
library thermion_flutter_js;
|
|
||||||
|
|
||||||
import 'dart:js_interop';
|
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
|
||||||
|
|
||||||
///
|
|
||||||
/// An extension type on [JSObject] that represents a
|
|
||||||
/// Javascript shim implementation for the [ThermionViewer] interface.
|
|
||||||
///
|
|
||||||
extension type ThermionDartAPIJSShim(JSObject _) implements JSObject {
|
|
||||||
|
|
||||||
@JS('wasm_test')
|
|
||||||
external JSPromise wasm_test(String str);
|
|
||||||
|
|
||||||
@JS('set_rendering')
|
|
||||||
external JSPromise set_rendering(bool render);
|
|
||||||
|
|
||||||
@JS('render')
|
|
||||||
external JSPromise render();
|
|
||||||
|
|
||||||
@JS('setFrameRate')
|
|
||||||
external JSPromise setFrameRate(int framerate);
|
|
||||||
|
|
||||||
@JS('setBackgroundImage')
|
|
||||||
external JSPromise setBackgroundImage(String path, bool fillHeight);
|
|
||||||
|
|
||||||
@JS('setBackgroundImagePosition')
|
|
||||||
external JSPromise setBackgroundImagePosition(double x, double y, bool clamp);
|
|
||||||
|
|
||||||
@JS('clearBackgroundImage')
|
|
||||||
external JSPromise clearBackgroundImage();
|
|
||||||
|
|
||||||
@JS('setBackgroundColor')
|
|
||||||
external JSPromise setBackgroundColor(
|
|
||||||
double r, double g, double b, double alpha);
|
|
||||||
|
|
||||||
@JS('loadSkybox')
|
|
||||||
external JSPromise loadSkybox(String skyboxPath);
|
|
||||||
|
|
||||||
@JS('removeSkybox')
|
|
||||||
external JSPromise removeSkybox();
|
|
||||||
|
|
||||||
@JS('loadIbl')
|
|
||||||
external JSPromise loadIbl(String lightingPath, double intensity);
|
|
||||||
|
|
||||||
@JS('rotateIbl')
|
|
||||||
external JSPromise rotateIbl(JSArray<JSNumber> rotationMatrix);
|
|
||||||
|
|
||||||
@JS('removeIbl')
|
|
||||||
external JSPromise removeIbl();
|
|
||||||
|
|
||||||
@JS('addLight')
|
|
||||||
external JSPromise<JSNumber> addLight(
|
|
||||||
int type,
|
|
||||||
double colour,
|
|
||||||
double intensity,
|
|
||||||
double posX,
|
|
||||||
double posY,
|
|
||||||
double posZ,
|
|
||||||
double dirX,
|
|
||||||
double dirY,
|
|
||||||
double dirZ,
|
|
||||||
double falloffRadius,
|
|
||||||
double spotLightConeInner,
|
|
||||||
double spotLightConeOuter,
|
|
||||||
double sunAngularRadius,
|
|
||||||
double sunHaloSize,
|
|
||||||
double sunHaloFallof,
|
|
||||||
bool castShadows);
|
|
||||||
|
|
||||||
@JS('removeLight')
|
|
||||||
external JSPromise removeLight(ThermionEntity light);
|
|
||||||
|
|
||||||
@JS('clearLights')
|
|
||||||
external JSPromise clearLights();
|
|
||||||
|
|
||||||
@JS('loadGlb')
|
|
||||||
external JSPromise<JSNumber> loadGlb(String path, int numInstances);
|
|
||||||
|
|
||||||
@JS('createInstance')
|
|
||||||
external JSPromise<JSNumber> createInstance(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('getInstanceCount')
|
|
||||||
external JSPromise<JSNumber> getInstanceCount(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('getInstances')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getInstances(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('loadGltf')
|
|
||||||
external JSPromise<JSNumber> loadGltf(
|
|
||||||
String path, String relativeResourcePath);
|
|
||||||
|
|
||||||
@JS('panStart')
|
|
||||||
external JSPromise panStart(double x, double y);
|
|
||||||
|
|
||||||
@JS('panUpdate')
|
|
||||||
external JSPromise panUpdate(double x, double y);
|
|
||||||
|
|
||||||
@JS('panEnd')
|
|
||||||
external JSPromise panEnd();
|
|
||||||
|
|
||||||
@JS('rotateStart')
|
|
||||||
external JSPromise rotateStart(double x, double y);
|
|
||||||
|
|
||||||
@JS('rotateUpdate')
|
|
||||||
external JSPromise rotateUpdate(double x, double y);
|
|
||||||
|
|
||||||
@JS('rotateEnd')
|
|
||||||
external JSPromise rotateEnd();
|
|
||||||
|
|
||||||
@JS('setMorphTargetWeights')
|
|
||||||
external JSPromise setMorphTargetWeights(
|
|
||||||
ThermionEntity entity, JSArray<JSNumber> weights);
|
|
||||||
|
|
||||||
@JS('getMorphTargetNames')
|
|
||||||
external JSPromise<JSArray<JSString>> getMorphTargetNames(
|
|
||||||
ThermionEntity entity, ThermionEntity childEntity);
|
|
||||||
|
|
||||||
@JS('getBoneNames')
|
|
||||||
external JSPromise<JSArray<JSString>> getBoneNames(
|
|
||||||
ThermionEntity entity, int skinIndex);
|
|
||||||
|
|
||||||
@JS('getAnimationNames')
|
|
||||||
external JSPromise<JSArray<JSString>> getAnimationNames(
|
|
||||||
ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('getAnimationDuration')
|
|
||||||
external JSPromise<JSNumber> getAnimationDuration(
|
|
||||||
ThermionEntity entity, int animationIndex);
|
|
||||||
|
|
||||||
@JS('setMorphAnimationData')
|
|
||||||
external JSPromise setMorphAnimationData(
|
|
||||||
ThermionEntity entity,
|
|
||||||
JSArray<JSArray<JSNumber>> animation,
|
|
||||||
JSArray<JSString> morphTargets,
|
|
||||||
JSArray<JSString>? targetMeshNames,
|
|
||||||
double frameLengthInMs);
|
|
||||||
|
|
||||||
@JS('resetBones')
|
|
||||||
external JSPromise resetBones(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('addBoneAnimation')
|
|
||||||
external JSPromise addBoneAnimation(
|
|
||||||
ThermionEntity entity,
|
|
||||||
JSArray<JSString> bones,
|
|
||||||
JSArray<JSArray<JSArray<JSNumber>>> frameData,
|
|
||||||
JSNumber frameLengthInMs,
|
|
||||||
JSNumber spaceEnum,
|
|
||||||
JSNumber skinIndex,
|
|
||||||
JSNumber fadeInInSecs,
|
|
||||||
JSNumber fadeOutInSecs,
|
|
||||||
JSNumber maxDelta);
|
|
||||||
|
|
||||||
@JS('removeEntity')
|
|
||||||
external JSPromise removeEntity(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('clearEntities')
|
|
||||||
external JSPromise clearEntities();
|
|
||||||
|
|
||||||
@JS('zoomBegin')
|
|
||||||
external JSPromise zoomBegin();
|
|
||||||
|
|
||||||
@JS('zoomUpdate')
|
|
||||||
external JSPromise zoomUpdate(double x, double y, double z);
|
|
||||||
|
|
||||||
@JS('zoomEnd')
|
|
||||||
external JSPromise zoomEnd();
|
|
||||||
|
|
||||||
@JS('playAnimation')
|
|
||||||
external JSPromise playAnimation(
|
|
||||||
ThermionEntity entity,
|
|
||||||
int index,
|
|
||||||
bool loop,
|
|
||||||
bool reverse,
|
|
||||||
bool replaceActive,
|
|
||||||
double crossfade,
|
|
||||||
);
|
|
||||||
|
|
||||||
@JS('playAnimationByName')
|
|
||||||
external JSPromise playAnimationByName(
|
|
||||||
ThermionEntity entity,
|
|
||||||
String name,
|
|
||||||
bool loop,
|
|
||||||
bool reverse,
|
|
||||||
bool replaceActive,
|
|
||||||
double crossfade,
|
|
||||||
);
|
|
||||||
|
|
||||||
@JS('setAnimationFrame')
|
|
||||||
external JSPromise setAnimationFrame(
|
|
||||||
ThermionEntity entity, int index, int animationFrame);
|
|
||||||
|
|
||||||
@JS('stopAnimation')
|
|
||||||
external JSPromise stopAnimation(ThermionEntity entity, int animationIndex);
|
|
||||||
|
|
||||||
@JS('stopAnimationByName')
|
|
||||||
external JSPromise stopAnimationByName(ThermionEntity entity, String name);
|
|
||||||
|
|
||||||
@JS('setCamera')
|
|
||||||
external JSPromise setCamera(ThermionEntity entity, String? name);
|
|
||||||
|
|
||||||
@JS('setMainCamera')
|
|
||||||
external JSPromise setMainCamera();
|
|
||||||
|
|
||||||
@JS('getMainCamera')
|
|
||||||
external JSPromise<JSNumber> getMainCamera();
|
|
||||||
|
|
||||||
@JS('setCameraFov')
|
|
||||||
external JSPromise setCameraFov(double degrees, double width, double height);
|
|
||||||
|
|
||||||
@JS('setToneMapping')
|
|
||||||
external JSPromise setToneMapping(int mapper);
|
|
||||||
|
|
||||||
@JS('setBloom')
|
|
||||||
external JSPromise setBloom(double bloom);
|
|
||||||
|
|
||||||
@JS('setCameraFocalLength')
|
|
||||||
external JSPromise setCameraFocalLength(double focalLength);
|
|
||||||
|
|
||||||
@JS('setCameraCulling')
|
|
||||||
external JSPromise setCameraCulling(double near, double far);
|
|
||||||
|
|
||||||
@JS('getCameraCullingNear')
|
|
||||||
external JSPromise<JSNumber> getCameraCullingNear();
|
|
||||||
|
|
||||||
@JS('getCameraCullingFar')
|
|
||||||
external JSPromise<JSNumber> getCameraCullingFar();
|
|
||||||
|
|
||||||
@JS('setCameraFocusDistance')
|
|
||||||
external JSPromise setCameraFocusDistance(double focusDistance);
|
|
||||||
|
|
||||||
@JS('getCameraPosition')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getCameraPosition();
|
|
||||||
|
|
||||||
@JS('getCameraModelMatrix')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getCameraModelMatrix();
|
|
||||||
|
|
||||||
@JS('getCameraViewMatrix')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getCameraViewMatrix();
|
|
||||||
|
|
||||||
@JS('getCameraProjectionMatrix')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getCameraProjectionMatrix();
|
|
||||||
|
|
||||||
@JS('getCameraCullingProjectionMatrix')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getCameraCullingProjectionMatrix();
|
|
||||||
|
|
||||||
@JS('getCameraFrustum')
|
|
||||||
external JSPromise<JSObject> getCameraFrustum();
|
|
||||||
|
|
||||||
@JS('setCameraPosition')
|
|
||||||
external JSPromise setCameraPosition(double x, double y, double z);
|
|
||||||
|
|
||||||
@JS('getCameraRotation')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getCameraRotation();
|
|
||||||
|
|
||||||
@JS('moveCameraToAsset')
|
|
||||||
external JSPromise moveCameraToAsset(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('setViewFrustumCulling')
|
|
||||||
external JSPromise setViewFrustumCulling(JSBoolean enabled);
|
|
||||||
|
|
||||||
@JS('setCameraExposure')
|
|
||||||
external JSPromise setCameraExposure(
|
|
||||||
double aperture, double shutterSpeed, double sensitivity);
|
|
||||||
|
|
||||||
@JS('setCameraRotation')
|
|
||||||
external JSPromise setCameraRotation(JSArray<JSNumber> quaternion);
|
|
||||||
|
|
||||||
@JS('setCameraModelMatrix')
|
|
||||||
external JSPromise setCameraModelMatrix(JSArray<JSNumber> matrix);
|
|
||||||
|
|
||||||
@JS('setMaterialColor')
|
|
||||||
external JSPromise setMaterialColor(ThermionEntity entity, String meshName,
|
|
||||||
int materialIndex, double r, double g, double b, double a);
|
|
||||||
|
|
||||||
@JS('transformToUnitCube')
|
|
||||||
external JSPromise transformToUnitCube(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('setPosition')
|
|
||||||
external JSPromise setPosition(
|
|
||||||
ThermionEntity entity, double x, double y, double z);
|
|
||||||
|
|
||||||
@JS('setScale')
|
|
||||||
external JSPromise setScale(ThermionEntity entity, double scale);
|
|
||||||
|
|
||||||
@JS('setRotation')
|
|
||||||
external JSPromise setRotation(
|
|
||||||
ThermionEntity entity, double rads, double x, double y, double z);
|
|
||||||
|
|
||||||
@JS('queuePositionUpdate')
|
|
||||||
external JSPromise queuePositionUpdate(
|
|
||||||
ThermionEntity entity, double x, double y, double z, bool relative);
|
|
||||||
|
|
||||||
@JS('queueRotationUpdate')
|
|
||||||
external JSPromise queueRotationUpdate(ThermionEntity entity, double rads,
|
|
||||||
double x, double y, double z, bool relative);
|
|
||||||
|
|
||||||
@JS('queueRotationUpdateQuat')
|
|
||||||
external JSPromise queueRotationUpdateQuat(
|
|
||||||
ThermionEntity entity, JSArray<JSNumber> quat, bool relative);
|
|
||||||
|
|
||||||
@JS('setPostProcessing')
|
|
||||||
external JSPromise setPostProcessing(bool enabled);
|
|
||||||
|
|
||||||
@JS('setAntiAliasing')
|
|
||||||
external JSPromise setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
|
||||||
|
|
||||||
@JS('setRotationQuat')
|
|
||||||
external JSPromise setRotationQuat(
|
|
||||||
ThermionEntity entity, JSArray<JSNumber> rotation);
|
|
||||||
|
|
||||||
@JS('reveal')
|
|
||||||
external JSPromise reveal(ThermionEntity entity, String? meshName);
|
|
||||||
|
|
||||||
@JS('hide')
|
|
||||||
external JSPromise hide(ThermionEntity entity, String? meshName);
|
|
||||||
|
|
||||||
@JS('pick')
|
|
||||||
external void pick(int x, int y);
|
|
||||||
|
|
||||||
@JS('getNameForEntity')
|
|
||||||
external String? getNameForEntity(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('setCameraManipulatorOptions')
|
|
||||||
external JSPromise setCameraManipulatorOptions(
|
|
||||||
int mode,
|
|
||||||
double orbitSpeedX,
|
|
||||||
double orbitSpeedY,
|
|
||||||
double zoomSpeed,
|
|
||||||
);
|
|
||||||
|
|
||||||
@JS('getChildEntities')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getChildEntities(
|
|
||||||
ThermionEntity parent, bool renderableOnly);
|
|
||||||
|
|
||||||
@JS('getChildEntity')
|
|
||||||
external JSPromise<JSNumber> getChildEntity(
|
|
||||||
ThermionEntity parent, String childName);
|
|
||||||
|
|
||||||
@JS('getChildEntityNames')
|
|
||||||
external JSPromise<JSArray<JSString>> getChildEntityNames(
|
|
||||||
ThermionEntity entity, bool renderableOnly);
|
|
||||||
|
|
||||||
@JS('setRecording')
|
|
||||||
external JSPromise setRecording(JSBoolean recording);
|
|
||||||
|
|
||||||
@JS('setRecordingOutputDirectory')
|
|
||||||
external JSPromise setRecordingOutputDirectory(String outputDirectory);
|
|
||||||
|
|
||||||
@JS('addAnimationComponent')
|
|
||||||
external JSPromise addAnimationComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('removeAnimationComponent')
|
|
||||||
external JSPromise removeAnimationComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('addCollisionComponent')
|
|
||||||
external JSPromise addCollisionComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('removeCollisionComponent')
|
|
||||||
external JSPromise removeCollisionComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('createGeometry')
|
|
||||||
external JSPromise<JSNumber> createGeometry(JSArray<JSNumber> vertices,
|
|
||||||
JSArray<JSNumber> indices, String? materialPath, int primitiveType);
|
|
||||||
|
|
||||||
@JS('setParent')
|
|
||||||
external JSPromise setParent(ThermionEntity child, ThermionEntity parent);
|
|
||||||
|
|
||||||
@JS('getParent')
|
|
||||||
external JSPromise<JSNumber> getParent(ThermionEntity child);
|
|
||||||
|
|
||||||
@JS('getParent')
|
|
||||||
external JSPromise<JSNumber> getBone(
|
|
||||||
ThermionEntity child, int boneIndex, int skinIndex);
|
|
||||||
|
|
||||||
@JS('testCollisions')
|
|
||||||
external JSPromise testCollisions(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('setPriority')
|
|
||||||
external JSPromise setPriority(ThermionEntity entityId, int priority);
|
|
||||||
|
|
||||||
@JS('getLocalTransform')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getLocalTransform(
|
|
||||||
ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('getWorldTransform')
|
|
||||||
external JSPromise<JSArray<JSNumber>> getWorldTransform(
|
|
||||||
ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('updateBoneMatrices')
|
|
||||||
external JSPromise updateBoneMatrices(ThermionEntity entity);
|
|
||||||
|
|
||||||
@JS('setTransform')
|
|
||||||
external JSPromise setTransform(
|
|
||||||
ThermionEntity entity, JSArray<JSNumber> transform);
|
|
||||||
|
|
||||||
@JS('setBoneTransform')
|
|
||||||
external JSPromise setBoneTransform(
|
|
||||||
ThermionEntity entity, int boneIndex, JSArray<JSNumber> transform, int skinIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
library thermion_flutter_js;
|
library thermion_flutter_js;
|
||||||
|
|
||||||
import 'dart:js_interop';
|
import 'dart:js_interop';
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/web/interop/shims/thermion_viewer_js_shim.dart';
|
import 'package:thermion_dart/thermion_dart/compatibility/web/interop/thermion_viewer_js_shim.dart';
|
||||||
|
|
||||||
import 'package:vector_math/vector_math_64.dart' as v64;
|
import 'package:vector_math/vector_math_64.dart' as v64;
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
@@ -15,19 +15,18 @@ import 'package:vector_math/vector_math_64.dart';
|
|||||||
/// A (Dart) class that wraps a (Dart) instance of [ThermionViewer],
|
/// A (Dart) class that wraps a (Dart) instance of [ThermionViewer],
|
||||||
/// but exported to JS by binding to a global property.
|
/// but exported to JS by binding to a global property.
|
||||||
/// This is effectively an implementation of [ThermionViewerJSShim];
|
/// This is effectively an implementation of [ThermionViewerJSShim];
|
||||||
/// allowing users to interact with an instance of [ThermionViewer]
|
/// allowing users to interact with an instance of [ThermionViewer]
|
||||||
/// (presumably compiled to WASM) from any Javascript context (including
|
/// (presumably compiled to WASM) from any Javascript context (including
|
||||||
/// the browser console).
|
/// the browser console).
|
||||||
///
|
///
|
||||||
@JSExport()
|
@JSExport()
|
||||||
class ThermionViewerFFIJSDartBridge {
|
class ThermionViewerJSDartBridge {
|
||||||
final ThermionViewer viewer;
|
final ThermionViewer viewer;
|
||||||
|
|
||||||
ThermionViewerFFIJSDartBridge(this.viewer);
|
ThermionViewerJSDartBridge(this.viewer);
|
||||||
|
|
||||||
void bind(
|
void bind({String globalPropertyName = "thermionViewer"}) {
|
||||||
{String globalPropertyName = "filamentViewer"}) {
|
var wrapper = createJSInteropWrapper<ThermionViewerJSDartBridge>(this)
|
||||||
var wrapper = createJSInteropWrapper<ThermionViewerFFIJSDartBridge>(this)
|
|
||||||
as ThermionViewerJSShim;
|
as ThermionViewerJSShim;
|
||||||
globalContext.setProperty(globalPropertyName.toJS, wrapper);
|
globalContext.setProperty(globalPropertyName.toJS, wrapper);
|
||||||
}
|
}
|
||||||
@@ -131,10 +130,13 @@ class ThermionViewerFFIJSDartBridge {
|
|||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise<JSNumber> loadGlb(String path, {int numInstances = 1}) {
|
JSPromise<JSNumber> loadGlb(String path, {int numInstances = 1}) {
|
||||||
|
print("Loading GLB from path $path with numInstances $numInstances");
|
||||||
return viewer
|
return viewer
|
||||||
.loadGlb(path, numInstances: numInstances)
|
.loadGlb(path, numInstances: numInstances)
|
||||||
.then((entity) => entity.toJS)
|
.then((entity) => entity.toJS)
|
||||||
.toJS;
|
.catchError((err) {
|
||||||
|
print("Error: $err");
|
||||||
|
}).toJS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
@@ -3,25 +3,26 @@ import 'dart:js_interop_unsafe';
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
import 'package:thermion_dart/thermion_dart/scene_impl.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
import 'shims/thermion_viewer_js_shim.dart';
|
import 'thermion_viewer_js_shim.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
/// An [ThermionViewer] implementation that forwards calls to
|
/// An [ThermionViewer] implementation that forwards calls to
|
||||||
/// a corresponding Javascript shim implementation (see [ThermionViewerJSShim]).
|
/// a corresponding Javascript shim implementation (see [ThermionViewerJSShim]).
|
||||||
///
|
///
|
||||||
class ThermionViewerFFIJS implements ThermionViewer {
|
class ThermionViewerJS implements ThermionViewer {
|
||||||
late final ThermionViewerJSShim _shim;
|
late final ThermionViewerJSShim _shim;
|
||||||
|
|
||||||
ThermionViewerFFIJS.fromGlobalProperty(String globalPropertyName) {
|
ThermionViewerJS.fromGlobalProperty(String globalPropertyName) {
|
||||||
this._shim = globalContext.getProperty(globalPropertyName.toJS)
|
this._shim = globalContext.getProperty(globalPropertyName.toJS)
|
||||||
as ThermionViewerJSShim;
|
as ThermionViewerJSShim;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThermionViewerFFIJS(this._shim);
|
ThermionViewerJS(this._shim);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<bool> get initialized async {
|
Future<bool> get initialized async {
|
||||||
@@ -56,6 +57,9 @@ class ThermionViewerFFIJS implements ThermionViewer {
|
|||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
await _shim.dispose().toDart;
|
await _shim.dispose().toDart;
|
||||||
|
for (final callback in _onDispose) {
|
||||||
|
callback.call();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -813,4 +817,13 @@ class ThermionViewerFFIJS implements ThermionViewer {
|
|||||||
Future updateBoneMatrices(ThermionEntity entity) {
|
Future updateBoneMatrices(ThermionEntity entity) {
|
||||||
return _shim.updateBoneMatrices(entity).toDart;
|
return _shim.updateBoneMatrices(entity).toDart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final _onDispose = <Future Function()>[];
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
void onDispose(Future Function() callback) {
|
||||||
|
_onDispose.add(callback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,120 +1,48 @@
|
|||||||
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'thermion_viewer.dart';
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// For now, this class just holds the entities that have been loaded (though not necessarily visible in the Filament Scene).
|
/// For now, this class just holds the entities that have been loaded (though not necessarily visible in the Filament Scene).
|
||||||
///
|
///
|
||||||
class SceneImpl extends Scene {
|
abstract class Scene {
|
||||||
|
///
|
||||||
ThermionViewer controller;
|
/// The last entity clicked/tapped in the viewport (internally, the result of calling pick);
|
||||||
|
|
||||||
SceneImpl(this.controller);
|
|
||||||
|
|
||||||
@override
|
|
||||||
ThermionEntity? selected;
|
ThermionEntity? selected;
|
||||||
|
|
||||||
final _onUpdatedController = StreamController<bool>.broadcast();
|
///
|
||||||
@override
|
/// A Stream updated whenever an entity is added/removed from the scene.
|
||||||
Stream<bool> get onUpdated => _onUpdatedController.stream;
|
///
|
||||||
|
Stream<bool> get onUpdated;
|
||||||
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).
|
/// 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.
|
||||||
///
|
///
|
||||||
Iterable<ThermionEntity> listLights() {
|
Stream<ThermionEntity> get onLoad;
|
||||||
return _lights;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
///
|
||||||
Iterable<ThermionEntity> listEntities() {
|
/// A Stream containing every ThermionEntity removed from the scene (i.e. via [removeEntity], [clearEntities], [removeLight] or [clearLights]).
|
||||||
return _entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerSelected(ThermionEntity entity) {
|
Stream<ThermionEntity> get onUnload;
|
||||||
selected = entity;
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregisterSelected() {
|
///
|
||||||
selected = null;
|
/// Lists all light entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
||||||
_onUpdatedController.add(true);
|
///
|
||||||
}
|
Iterable<ThermionEntity> listLights();
|
||||||
|
|
||||||
@override
|
///
|
||||||
void select(ThermionEntity entity) {
|
/// Lists all entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
||||||
selected = entity;
|
///
|
||||||
controller.gizmo?.attach(entity);
|
Iterable<ThermionEntity> listEntities();
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
///
|
||||||
}
|
/// Attach the gizmo to the specified entity.
|
||||||
|
///
|
||||||
|
void select(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
void registerEntity(ThermionEntity entity);
|
||||||
|
|
||||||
|
}
|
||||||
125
thermion_dart/lib/thermion_dart/scene_impl.dart
Normal file
125
thermion_dart/lib/thermion_dart/scene_impl.dart
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
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,5 +1,6 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
@@ -279,11 +280,11 @@ abstract class ThermionViewer {
|
|||||||
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
|
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
|
||||||
/// the current active glTF animation ("animation1") and the animation you
|
/// the current active glTF animation ("animation1") and the animation you
|
||||||
/// set via this method ("animation2"). The bone orientations will be
|
/// set via this method ("animation2"). The bone orientations will be
|
||||||
/// linearly interpolated between animation1 and animation2; at time 0,
|
/// linearly interpolated between animation1 and animation2; at time 0,
|
||||||
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
|
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
|
||||||
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
|
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
|
||||||
/// This will be applied in reverse after [fadeOutInSecs].
|
/// This will be applied in reverse after [fadeOutInSecs].
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
||||||
{int skinIndex = 0,
|
{int skinIndex = 0,
|
||||||
@@ -701,51 +702,11 @@ abstract class ThermionViewer {
|
|||||||
///
|
///
|
||||||
///
|
///
|
||||||
AbstractGizmo? get gizmo;
|
AbstractGizmo? get gizmo;
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// 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;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// A Stream updated whenever an entity is added/removed from the scene.
|
/// Register a callback to be invoked when this viewer is disposed.
|
||||||
///
|
///
|
||||||
Stream<bool> get onUpdated;
|
void onDispose(Future Function() callback);
|
||||||
|
|
||||||
///
|
|
||||||
/// 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;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// A Stream containing every ThermionEntity removed from the scene (i.e. via [removeEntity], [clearEntities], [removeLight] or [clearLights]).
|
|
||||||
|
|
||||||
Stream<ThermionEntity> get onUnload;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Lists all light entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
|
||||||
///
|
|
||||||
Iterable<ThermionEntity> listLights();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Lists all entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
|
||||||
///
|
|
||||||
Iterable<ThermionEntity> listEntities();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Attach the gizmo to the specified entity.
|
|
||||||
///
|
|
||||||
void select(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
///
|
|
||||||
void registerEntity(ThermionEntity entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractGizmo {
|
abstract class AbstractGizmo {
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/compatibility.dart';
|
import 'package:thermion_dart/thermion_dart/compatibility/compatibility.dart';
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/entities/gizmo.dart';
|
import 'package:thermion_dart/thermion_dart/entities/gizmo.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
import 'thermion_viewer.dart';
|
import 'thermion_viewer.dart';
|
||||||
import 'scene.dart';
|
import 'scene_impl.dart';
|
||||||
import 'compatibility/compatibility.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
|
typedef ThermionViewerImpl = ThermionViewerFFI;
|
||||||
|
|
||||||
// ignore: constant_identifier_names
|
// ignore: constant_identifier_names
|
||||||
const ThermionEntity _FILAMENT_ASSET_ERROR = 0;
|
const ThermionEntity _FILAMENT_ASSET_ERROR = 0;
|
||||||
@@ -17,10 +17,10 @@ const ThermionEntity _FILAMENT_ASSET_ERROR = 0;
|
|||||||
typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
|
typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
|
||||||
|
|
||||||
class ThermionViewerFFI extends ThermionViewer {
|
class ThermionViewerFFI extends ThermionViewer {
|
||||||
final _compat = Compatibility();
|
final _logger = Logger("ThermionViewerFFI");
|
||||||
|
|
||||||
late SceneImpl _scene;
|
SceneImpl? _scene;
|
||||||
Scene get scene => _scene;
|
Scene get scene => _scene!;
|
||||||
|
|
||||||
double _pixelRatio = 1.0;
|
double _pixelRatio = 1.0;
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
NativeCallable<Void Function(Int32 entityId, Int x, Int y)>.listener(
|
NativeCallable<Void Function(Int32 entityId, Int x, Int y)>.listener(
|
||||||
_onPickResult);
|
_onPickResult);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
print(
|
_logger.severe(
|
||||||
"Failed to set pick result callback. This is expected if running on web/wasm");
|
"Failed to set pick result callback. This is expected if running on web/wasm");
|
||||||
}
|
}
|
||||||
_initialize();
|
_initialize();
|
||||||
@@ -172,14 +172,39 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
set_frame_interval_ffi(_viewer!, interval);
|
set_frame_interval_ffi(_viewer!, interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final _onDispose = <Future Function()>[];
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
@override
|
@override
|
||||||
Future dispose() async {
|
Future dispose() async {
|
||||||
|
if (_viewer == null) {
|
||||||
|
// we've already cleaned everything up, ignore the call to dispose
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await setRendering(false);
|
||||||
|
await clearEntities();
|
||||||
|
await clearLights();
|
||||||
|
await _scene!.dispose();
|
||||||
|
_scene = null;
|
||||||
destroy_filament_viewer_ffi(_viewer!);
|
destroy_filament_viewer_ffi(_viewer!);
|
||||||
|
|
||||||
_sceneManager = null;
|
_sceneManager = null;
|
||||||
_viewer = null;
|
_viewer = null;
|
||||||
|
await _pickResultController.close();
|
||||||
|
|
||||||
|
for (final callback in _onDispose) {
|
||||||
|
await callback.call();
|
||||||
|
}
|
||||||
|
_onDispose.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
void onDispose(Future Function() callback) {
|
||||||
|
_onDispose.add(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -317,7 +342,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
throw Exception("Failed to add light to scene");
|
throw Exception("Failed to add light to scene");
|
||||||
}
|
}
|
||||||
|
|
||||||
_scene.registerLight(entity);
|
_scene!.registerLight(entity);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,7 +351,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
///
|
///
|
||||||
@override
|
@override
|
||||||
Future removeLight(ThermionEntity entity) async {
|
Future removeLight(ThermionEntity entity) async {
|
||||||
_scene.unregisterLight(entity);
|
_scene!.unregisterLight(entity);
|
||||||
remove_light_ffi(_viewer!, entity);
|
remove_light_ffi(_viewer!, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,7 +362,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
Future clearLights() async {
|
Future clearLights() async {
|
||||||
clear_lights_ffi(_viewer!);
|
clear_lights_ffi(_viewer!);
|
||||||
|
|
||||||
_scene.clearLights();
|
_scene!.clearLights();
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -393,7 +418,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
if (entity == _FILAMENT_ASSET_ERROR) {
|
if (entity == _FILAMENT_ASSET_ERROR) {
|
||||||
throw Exception("An error occurred loading the asset at $path");
|
throw Exception("An error occurred loading the asset at $path");
|
||||||
}
|
}
|
||||||
_scene.registerEntity(entity);
|
_scene!.registerEntity(entity);
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@@ -404,11 +429,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
@override
|
@override
|
||||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||||
{bool force = false}) async {
|
{bool force = false}) async {
|
||||||
// if (Platform.isWindows && !force) {
|
|
||||||
// throw Exception(
|
|
||||||
// "loadGltf has a race condition on Windows which is likely to crash your program. If you really want to try, pass force=true to loadGltf");
|
|
||||||
// }
|
|
||||||
|
|
||||||
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
|
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
|
||||||
final relativeResourcePathPtr =
|
final relativeResourcePathPtr =
|
||||||
relativeResourcePath.toNativeUtf8(allocator: allocator).cast<Char>();
|
relativeResourcePath.toNativeUtf8(allocator: allocator).cast<Char>();
|
||||||
@@ -419,7 +439,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
if (entity == _FILAMENT_ASSET_ERROR) {
|
if (entity == _FILAMENT_ASSET_ERROR) {
|
||||||
throw Exception("An error occurred loading the asset at $path");
|
throw Exception("An error occurred loading the asset at $path");
|
||||||
}
|
}
|
||||||
_scene.registerEntity(entity);
|
_scene!.registerEntity(entity);
|
||||||
|
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@@ -608,14 +628,12 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
var meshEntity = meshEntities[i];
|
var meshEntity = meshEntities[i];
|
||||||
|
|
||||||
if (targetMeshNames?.contains(meshName) == false) {
|
if (targetMeshNames?.contains(meshName) == false) {
|
||||||
print("Skipping $meshName, not contained in target");
|
_logger.info("Skipping $meshName, not contained in target");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var meshMorphTargets = await getMorphTargetNames(entity, meshEntity);
|
var meshMorphTargets = await getMorphTargetNames(entity, meshEntity);
|
||||||
|
|
||||||
print("Got mesh morph targets ${meshMorphTargets}");
|
|
||||||
|
|
||||||
var intersection = animation.morphTargets
|
var intersection = animation.morphTargets
|
||||||
.toSet()
|
.toSet()
|
||||||
.intersection(meshMorphTargets.toSet())
|
.intersection(meshMorphTargets.toSet())
|
||||||
@@ -676,8 +694,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
||||||
{int skinIndex = 0,
|
{int skinIndex = 0,
|
||||||
double fadeOutInSecs = 0.0,
|
double fadeOutInSecs = 0.0,
|
||||||
double fadeInInSecs = 0.0,
|
double fadeInInSecs = 0.0,
|
||||||
double maxDelta=1.0}) async {
|
double maxDelta = 1.0}) async {
|
||||||
if (animation.space != Space.Bone &&
|
if (animation.space != Space.Bone &&
|
||||||
animation.space != Space.ParentWorldRotation) {
|
animation.space != Space.ParentWorldRotation) {
|
||||||
throw UnimplementedError("TODO - support ${animation.space}");
|
throw UnimplementedError("TODO - support ${animation.space}");
|
||||||
@@ -710,7 +728,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
var boneName = animation.bones[i];
|
var boneName = animation.bones[i];
|
||||||
var entityBoneIndex = boneNames.indexOf(boneName);
|
var entityBoneIndex = boneNames.indexOf(boneName);
|
||||||
if (entityBoneIndex == -1) {
|
if (entityBoneIndex == -1) {
|
||||||
print("Warning : bone $boneName not found, skipping");
|
_logger.warning("Bone $boneName not found, skipping");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var boneEntity = bones[entityBoneIndex];
|
var boneEntity = bones[entityBoneIndex];
|
||||||
@@ -720,7 +738,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
var world = Matrix4.identity();
|
var world = Matrix4.identity();
|
||||||
// this odd use of ! is intentional, without it, the WASM optimizer gets in trouble
|
// this odd use of ! is intentional, without it, the WASM optimizer gets in trouble
|
||||||
var parentBoneEntity = (await getParent(boneEntity))!;
|
var parentBoneEntity = (await getParent(boneEntity))!;
|
||||||
while(true) {
|
while (true) {
|
||||||
if (!bones.contains(parentBoneEntity!)) {
|
if (!bones.contains(parentBoneEntity!)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -758,7 +776,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
numFrames,
|
numFrames,
|
||||||
animation.frameLengthInMs,
|
animation.frameLengthInMs,
|
||||||
fadeOutInSecs,
|
fadeOutInSecs,
|
||||||
fadeInInSecs,
|
fadeInInSecs,
|
||||||
maxDelta);
|
maxDelta);
|
||||||
}
|
}
|
||||||
allocator.free(data);
|
allocator.free(data);
|
||||||
@@ -894,7 +912,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
///
|
///
|
||||||
@override
|
@override
|
||||||
Future removeEntity(ThermionEntity entity) async {
|
Future removeEntity(ThermionEntity entity) async {
|
||||||
_scene.unregisterEntity(entity);
|
_scene!.unregisterEntity(entity);
|
||||||
|
|
||||||
await withVoidCallback(
|
await withVoidCallback(
|
||||||
(callback) => remove_entity_ffi(_viewer!, entity, callback));
|
(callback) => remove_entity_ffi(_viewer!, entity, callback));
|
||||||
@@ -911,7 +929,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
await withVoidCallback((callback) {
|
await withVoidCallback((callback) {
|
||||||
clear_entities_ffi(_viewer!, callback);
|
clear_entities_ffi(_viewer!, callback);
|
||||||
});
|
});
|
||||||
_scene.clearEntities();
|
_scene!.clearEntities();
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -984,7 +1002,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
var animations = await getAnimationNames(entity);
|
var animations = await getAnimationNames(entity);
|
||||||
var index = animations.indexOf(name);
|
var index = animations.indexOf(name);
|
||||||
var duration = await getAnimationDuration(entity, index);
|
var duration = await getAnimationDuration(entity, index);
|
||||||
print("Duration for $name : $duration");
|
|
||||||
await playAnimation(entity, index,
|
await playAnimation(entity, index,
|
||||||
loop: loop,
|
loop: loop,
|
||||||
reverse: reverse,
|
reverse: reverse,
|
||||||
@@ -1296,7 +1313,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
x: (x / _pixelRatio).toDouble(),
|
x: (x / _pixelRatio).toDouble(),
|
||||||
y: (viewportDimensions.$2 - y) / _pixelRatio
|
y: (viewportDimensions.$2 - y) / _pixelRatio
|
||||||
));
|
));
|
||||||
_scene.registerSelected(entityId);
|
_scene!.registerSelected(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
late NativeCallable<Void Function(Int32 entityId, Int x, Int y)>
|
late NativeCallable<Void Function(Int32 entityId, Int x, Int y)>
|
||||||
@@ -1307,7 +1324,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
///
|
///
|
||||||
@override
|
@override
|
||||||
void pick(int x, int y) async {
|
void pick(int x, int y) async {
|
||||||
_scene.unregisterSelected();
|
_scene!.unregisterSelected();
|
||||||
|
|
||||||
filament_pick(
|
filament_pick(
|
||||||
_viewer!,
|
_viewer!,
|
||||||
@@ -1414,9 +1431,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
throw Exception("No viewer available");
|
throw Exception("No viewer available");
|
||||||
}
|
}
|
||||||
|
|
||||||
print(
|
|
||||||
"WARNING: getCameraProjectionMatrix and getCameraCullingProjectionMatrix are not reliable. Consider these broken");
|
|
||||||
|
|
||||||
var arrayPtr = get_camera_projection_matrix(_viewer!);
|
var arrayPtr = get_camera_projection_matrix(_viewer!);
|
||||||
var doubleList = arrayPtr.asTypedList(16);
|
var doubleList = arrayPtr.asTypedList(16);
|
||||||
var projectionMatrix = Matrix4.fromList(doubleList);
|
var projectionMatrix = Matrix4.fromList(doubleList);
|
||||||
@@ -1432,7 +1446,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
if (_viewer == null) {
|
if (_viewer == null) {
|
||||||
throw Exception("No viewer available");
|
throw Exception("No viewer available");
|
||||||
}
|
}
|
||||||
print(
|
throw Exception(
|
||||||
"WARNING: getCameraProjectionMatrix and getCameraCullingProjectionMatrix are not reliable. Consider these broken");
|
"WARNING: getCameraProjectionMatrix and getCameraCullingProjectionMatrix are not reliable. Consider these broken");
|
||||||
var arrayPtr = get_camera_culling_projection_matrix(_viewer!);
|
var arrayPtr = get_camera_culling_projection_matrix(_viewer!);
|
||||||
var doubleList = arrayPtr.asTypedList(16);
|
var doubleList = arrayPtr.asTypedList(16);
|
||||||
@@ -1451,7 +1465,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
}
|
}
|
||||||
var arrayPtr = get_camera_frustum(_viewer!);
|
var arrayPtr = get_camera_frustum(_viewer!);
|
||||||
var doubleList = arrayPtr.asTypedList(24);
|
var doubleList = arrayPtr.asTypedList(24);
|
||||||
print(doubleList);
|
|
||||||
|
|
||||||
var frustum = Frustum();
|
var frustum = Frustum();
|
||||||
frustum.plane0.setFromComponents(
|
frustum.plane0.setFromComponents(
|
||||||
@@ -1624,7 +1637,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
throw Exception("Failed to create geometry");
|
throw Exception("Failed to create geometry");
|
||||||
}
|
}
|
||||||
|
|
||||||
_scene.registerEntity(entity);
|
_scene!.registerEntity(entity);
|
||||||
|
|
||||||
allocator.free(materialPathPtr);
|
allocator.free(materialPathPtr);
|
||||||
allocator.free(vertexPtr);
|
allocator.free(vertexPtr);
|
||||||
|
|||||||
729
thermion_dart/lib/thermion_dart/thermion_viewer_stub.dart
Normal file
729
thermion_dart/lib/thermion_dart/thermion_viewer_stub.dart
Normal file
@@ -0,0 +1,729 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:thermion_dart/thermion_dart/scene.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.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) {
|
||||||
|
// TODO: implement addAnimationComponent
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
||||||
|
{int skinIndex = 0,
|
||||||
|
double fadeInInSecs = 0.0,
|
||||||
|
double fadeOutInSecs = 0.0,
|
||||||
|
double maxDelta = 1.0}) {
|
||||||
|
// TODO: implement addBoneAnimation
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future addCollisionComponent(ThermionEntity entity,
|
||||||
|
{void Function(int entityId1, int entityId2)? callback,
|
||||||
|
bool affectsTransform = false}) {
|
||||||
|
// TODO: implement addCollisionComponent
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
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}) {
|
||||||
|
// TODO: implement addLight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future clearBackgroundImage() {
|
||||||
|
// TODO: implement clearBackgroundImage
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future clearEntities() {
|
||||||
|
// TODO: implement clearEntities
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future clearLights() {
|
||||||
|
// TODO: implement clearLights
|
||||||
|
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) {
|
||||||
|
// TODO: implement createInstance
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future dispose() {
|
||||||
|
// TODO: implement dispose
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getAnimationDuration(
|
||||||
|
ThermionEntity entity, int animationIndex) {
|
||||||
|
// TODO: implement getAnimationDuration
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> getAnimationNames(ThermionEntity entity) {
|
||||||
|
// TODO: implement getAnimationNames
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
|
||||||
|
{int skinIndex = 0}) {
|
||||||
|
// TODO: implement getBone
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> getBoneNames(ThermionEntity entity,
|
||||||
|
{int skinIndex = 0}) {
|
||||||
|
// TODO: implement getBoneNames
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCameraCullingFar() {
|
||||||
|
// TODO: implement getCameraCullingFar
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCameraCullingNear() {
|
||||||
|
// TODO: implement getCameraCullingNear
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getCameraCullingProjectionMatrix() {
|
||||||
|
// TODO: implement getCameraCullingProjectionMatrix
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Frustum> getCameraFrustum() {
|
||||||
|
// TODO: implement getCameraFrustum
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getCameraModelMatrix() {
|
||||||
|
// TODO: implement getCameraModelMatrix
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Vector3> getCameraPosition() {
|
||||||
|
// TODO: implement getCameraPosition
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getCameraProjectionMatrix() {
|
||||||
|
// TODO: implement getCameraProjectionMatrix
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix3> getCameraRotation() {
|
||||||
|
// TODO: implement getCameraRotation
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getCameraViewMatrix() {
|
||||||
|
// TODO: implement getCameraViewMatrix
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ThermionEntity>> getChildEntities(
|
||||||
|
ThermionEntity parent, bool renderableOnly) {
|
||||||
|
// TODO: implement getChildEntities
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> getChildEntity(
|
||||||
|
ThermionEntity parent, String childName) {
|
||||||
|
// TODO: implement getChildEntity
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> getChildEntityNames(ThermionEntity entity,
|
||||||
|
{bool renderableOnly = true}) {
|
||||||
|
// TODO: implement getChildEntityNames
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<int> getInstanceCount(ThermionEntity entity) {
|
||||||
|
// TODO: implement getInstanceCount
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<ThermionEntity>> getInstances(ThermionEntity entity) {
|
||||||
|
// TODO: implement getInstances
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
|
||||||
|
{int skinIndex = 0}) {
|
||||||
|
// TODO: implement getInverseBindMatrix
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getLocalTransform(ThermionEntity entity) {
|
||||||
|
// TODO: implement getLocalTransform
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> getMainCamera() {
|
||||||
|
// TODO: implement getMainCamera
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<String>> getMorphTargetNames(
|
||||||
|
ThermionEntity entity, ThermionEntity childEntity) {
|
||||||
|
// TODO: implement getMorphTargetNames
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? getNameForEntity(ThermionEntity entity) {
|
||||||
|
// TODO: implement getNameForEntity
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity?> getParent(ThermionEntity child) {
|
||||||
|
// TODO: implement getParent
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Matrix4> getWorldTransform(ThermionEntity entity) {
|
||||||
|
// TODO: implement getWorldTransform
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement gizmo
|
||||||
|
AbstractGizmo? get gizmo => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future hide(ThermionEntity entity, String? meshName) {
|
||||||
|
// TODO: implement hide
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// 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
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future loadSkybox(String skyboxPath) {
|
||||||
|
// TODO: implement loadSkybox
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future moveCameraToAsset(ThermionEntity entity) {
|
||||||
|
// TODO: implement moveCameraToAsset
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onDispose(Future Function() callback) {
|
||||||
|
// TODO: implement onDispose
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future panEnd() {
|
||||||
|
// TODO: implement panEnd
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future panStart(double x, double y) {
|
||||||
|
// TODO: implement panStart
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future panUpdate(double x, double y) {
|
||||||
|
// TODO: implement panUpdate
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void pick(int x, int y) {
|
||||||
|
// TODO: implement pick
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement pickResult
|
||||||
|
Stream<FilamentPickResult> get pickResult => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future playAnimation(ThermionEntity entity, int index,
|
||||||
|
{bool loop = false,
|
||||||
|
bool reverse = false,
|
||||||
|
bool replaceActive = true,
|
||||||
|
double crossfade = 0.0}) {
|
||||||
|
// TODO: implement playAnimation
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future playAnimationByName(ThermionEntity entity, String name,
|
||||||
|
{bool loop = false,
|
||||||
|
bool reverse = false,
|
||||||
|
bool replaceActive = true,
|
||||||
|
double crossfade = 0.0}) {
|
||||||
|
// TODO: implement playAnimationByName
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queuePositionUpdate(
|
||||||
|
ThermionEntity entity, double x, double y, double z,
|
||||||
|
{bool relative = false}) {
|
||||||
|
// TODO: implement queuePositionUpdate
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queueRotationUpdate(
|
||||||
|
ThermionEntity entity, double rads, double x, double y, double z,
|
||||||
|
{bool relative = false}) {
|
||||||
|
// TODO: implement queueRotationUpdate
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
|
||||||
|
{bool relative = false}) {
|
||||||
|
// TODO: implement queueRotationUpdateQuat
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeAnimationComponent(ThermionEntity entity) {
|
||||||
|
// TODO: implement removeAnimationComponent
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeCollisionComponent(ThermionEntity entity) {
|
||||||
|
// TODO: implement removeCollisionComponent
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeEntity(ThermionEntity entity) {
|
||||||
|
// TODO: implement removeEntity
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeIbl() {
|
||||||
|
// TODO: implement removeIbl
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeLight(ThermionEntity light) {
|
||||||
|
// TODO: implement removeLight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeSkybox() {
|
||||||
|
// TODO: implement removeSkybox
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future render() {
|
||||||
|
// TODO: implement render
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement rendering
|
||||||
|
bool get rendering => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future resetBones(ThermionEntity entity) {
|
||||||
|
// TODO: implement resetBones
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future reveal(ThermionEntity entity, String? meshName) {
|
||||||
|
// TODO: implement reveal
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future rotateEnd() {
|
||||||
|
// TODO: implement rotateEnd
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future rotateIbl(Matrix3 rotation) {
|
||||||
|
// TODO: implement rotateIbl
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future rotateStart(double x, double y) {
|
||||||
|
// TODO: implement rotateStart
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future rotateUpdate(double x, double y) {
|
||||||
|
// TODO: implement rotateUpdate
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement scene
|
||||||
|
Scene get scene => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setAnimationFrame(
|
||||||
|
ThermionEntity entity, int index, int animationFrame) {
|
||||||
|
// TODO: implement setAnimationFrame
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) {
|
||||||
|
// TODO: implement setAntiAliasing
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setBackgroundColor(double r, double g, double b, double alpha) {
|
||||||
|
// TODO: implement setBackgroundColor
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setBackgroundImage(String path, {bool fillHeight = false}) {
|
||||||
|
// TODO: implement setBackgroundImage
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setBackgroundImagePosition(double x, double y, {bool clamp = false}) {
|
||||||
|
// TODO: implement setBackgroundImagePosition
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setBloom(double bloom) {
|
||||||
|
// TODO: implement setBloom
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setBoneTransform(
|
||||||
|
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
||||||
|
{int skinIndex = 0}) {
|
||||||
|
// TODO: implement setBoneTransform
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCamera(ThermionEntity entity, String? name) {
|
||||||
|
// TODO: implement setCamera
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraCulling(double near, double far) {
|
||||||
|
// TODO: implement setCameraCulling
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraExposure(
|
||||||
|
double aperture, double shutterSpeed, double sensitivity) {
|
||||||
|
// TODO: implement setCameraExposure
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraFocalLength(double focalLength) {
|
||||||
|
// TODO: implement setCameraFocalLength
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraFocusDistance(double focusDistance) {
|
||||||
|
// TODO: implement setCameraFocusDistance
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraFov(double degrees, double width, double height) {
|
||||||
|
// TODO: implement setCameraFov
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraManipulatorOptions(
|
||||||
|
{ManipulatorMode mode = ManipulatorMode.ORBIT,
|
||||||
|
double orbitSpeedX = 0.01,
|
||||||
|
double orbitSpeedY = 0.01,
|
||||||
|
double zoomSpeed = 0.01}) {
|
||||||
|
// TODO: implement setCameraManipulatorOptions
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraModelMatrix(List<double> matrix) {
|
||||||
|
// TODO: implement setCameraModelMatrix
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraPosition(double x, double y, double z) {
|
||||||
|
// TODO: implement setCameraPosition
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraRotation(Quaternion quaternion) {
|
||||||
|
// TODO: implement setCameraRotation
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setFrameRate(int framerate) {
|
||||||
|
// TODO: implement setFrameRate
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMainCamera() {
|
||||||
|
// TODO: implement setMainCamera
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialColor(ThermionEntity entity, String meshName,
|
||||||
|
int materialIndex, double r, double g, double b, double a) {
|
||||||
|
// TODO: implement setMaterialColor
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMorphAnimationData(
|
||||||
|
ThermionEntity entity, MorphAnimationData animation,
|
||||||
|
{List<String>? targetMeshNames}) {
|
||||||
|
// TODO: implement setMorphAnimationData
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights) {
|
||||||
|
// TODO: implement setMorphTargetWeights
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setParent(ThermionEntity child, ThermionEntity parent) {
|
||||||
|
// TODO: implement setParent
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setPosition(ThermionEntity entity, double x, double y, double z) {
|
||||||
|
// TODO: implement setPosition
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setPostProcessing(bool enabled) {
|
||||||
|
// TODO: implement setPostProcessing
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setPriority(ThermionEntity entityId, int priority) {
|
||||||
|
// TODO: implement setPriority
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setRecording(bool recording) {
|
||||||
|
// TODO: implement setRecording
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setRecordingOutputDirectory(String outputDirectory) {
|
||||||
|
// TODO: implement setRecordingOutputDirectory
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setRendering(bool render) {
|
||||||
|
// TODO: implement setRendering
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setRotation(
|
||||||
|
ThermionEntity entity, double rads, double x, double y, double z) {
|
||||||
|
// TODO: implement setRotation
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setRotationQuat(ThermionEntity entity, Quaternion rotation) {
|
||||||
|
// TODO: implement setRotationQuat
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setScale(ThermionEntity entity, double scale) {
|
||||||
|
// TODO: implement setScale
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setToneMapping(ToneMapper mapper) {
|
||||||
|
// TODO: implement setToneMapping
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setTransform(ThermionEntity entity, Matrix4 transform) {
|
||||||
|
// TODO: implement setTransform
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setViewFrustumCulling(bool enabled) {
|
||||||
|
// TODO: implement setViewFrustumCulling
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future stopAnimation(ThermionEntity entity, int animationIndex) {
|
||||||
|
// TODO: implement stopAnimation
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future stopAnimationByName(ThermionEntity entity, String name) {
|
||||||
|
// TODO: implement stopAnimationByName
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future testCollisions(ThermionEntity entity) {
|
||||||
|
// TODO: implement testCollisions
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future transformToUnitCube(ThermionEntity entity) {
|
||||||
|
// TODO: implement transformToUnitCube
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future updateBoneMatrices(ThermionEntity entity) {
|
||||||
|
// TODO: implement updateBoneMatrices
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future zoomBegin() {
|
||||||
|
// TODO: implement zoomBegin
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future zoomEnd() {
|
||||||
|
// TODO: implement zoomEnd
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future zoomUpdate(double x, double y, double z) {
|
||||||
|
// TODO: implement zoomUpdate
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -211,6 +211,7 @@ namespace thermion_filament
|
|||||||
uint32_t _imageWidth = 0;
|
uint32_t _imageWidth = 0;
|
||||||
mat4f _imageScale;
|
mat4f _imageScale;
|
||||||
Texture *_imageTexture = nullptr;
|
Texture *_imageTexture = nullptr;
|
||||||
|
Texture *_dummyImageTexture = nullptr;
|
||||||
utils::Entity _imageEntity;
|
utils::Entity _imageEntity;
|
||||||
VertexBuffer *_imageVb = nullptr;
|
VertexBuffer *_imageVb = nullptr;
|
||||||
IndexBuffer *_imageIb = nullptr;
|
IndexBuffer *_imageIb = nullptr;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
|
|
||||||
#include "ResourceBuffer.h"
|
#include "ResourceBuffer.h"
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
#ifndef __EMSCRIPTEN__
|
#ifndef __EMSCRIPTEN__
|
||||||
#include <thread>
|
#include <thread>
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
@@ -15,6 +14,15 @@ namespace thermion_filament
|
|||||||
struct ResourceLoaderWrapperImpl : public ResourceLoaderWrapper
|
struct ResourceLoaderWrapperImpl : public ResourceLoaderWrapper
|
||||||
{
|
{
|
||||||
|
|
||||||
|
ResourceLoaderWrapperImpl(ResourceLoaderWrapper* wrapper) {
|
||||||
|
loadFromOwner = wrapper->loadFromOwner;
|
||||||
|
freeFromOwner = wrapper->freeFromOwner;
|
||||||
|
loadResource = wrapper->loadResource;
|
||||||
|
freeResource = wrapper->freeResource;
|
||||||
|
owner = wrapper->owner;
|
||||||
|
loadToOut = wrapper->loadToOut;
|
||||||
|
}
|
||||||
|
|
||||||
ResourceLoaderWrapperImpl(LoadFilamentResource loader, FreeFilamentResource freeResource)
|
ResourceLoaderWrapperImpl(LoadFilamentResource loader, FreeFilamentResource freeResource)
|
||||||
{
|
{
|
||||||
loadFromOwner = nullptr;
|
loadFromOwner = nullptr;
|
||||||
@@ -73,4 +81,3 @@ namespace thermion_filament
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|||||||
@@ -179,7 +179,6 @@ namespace thermion_filament
|
|||||||
gltfio::TextureProvider *_stbDecoder = nullptr;
|
gltfio::TextureProvider *_stbDecoder = nullptr;
|
||||||
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
Material *_gizmoMaterial;
|
|
||||||
|
|
||||||
utils::NameComponentManager *_ncm;
|
utils::NameComponentManager *_ncm;
|
||||||
|
|
||||||
@@ -201,8 +200,9 @@ namespace thermion_filament
|
|||||||
const char *entityName);
|
const char *entityName);
|
||||||
|
|
||||||
EntityId addGizmo();
|
EntityId addGizmo();
|
||||||
utils::Entity _gizmoX;
|
utils::Entity _gizmo[3];
|
||||||
utils::Entity _gizmoY;
|
Material* _gizmoMaterial;
|
||||||
utils::Entity _gizmoZ;
|
MaterialInstance* _gizmoMaterialInstances[3];
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,11 +126,10 @@ namespace thermion_filament
|
|||||||
|
|
||||||
static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2};
|
static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2};
|
||||||
|
|
||||||
FilamentViewer::FilamentViewer(const void *sharedContext, const ResourceLoaderWrapperImpl *const ResourceLoaderWrapperImpl, void *const platform, const char *uberArchivePath)
|
FilamentViewer::FilamentViewer(const void *sharedContext, const ResourceLoaderWrapperImpl *const resourceLoader, void *const platform, const char *uberArchivePath)
|
||||||
: _resourceLoaderWrapper(ResourceLoaderWrapperImpl)
|
: _resourceLoaderWrapper(resourceLoader)
|
||||||
{
|
{
|
||||||
_context = (void*) sharedContext;
|
_context = (void*) sharedContext;
|
||||||
|
|
||||||
ASSERT_POSTCONDITION(_resourceLoaderWrapper != nullptr, "Resource loader must be non-null");
|
ASSERT_POSTCONDITION(_resourceLoaderWrapper != nullptr, "Resource loader must be non-null");
|
||||||
|
|
||||||
#if TARGET_OS_IPHONE
|
#if TARGET_OS_IPHONE
|
||||||
@@ -215,7 +214,7 @@ namespace thermion_filament
|
|||||||
|
|
||||||
Log("Created scene maager");
|
Log("Created scene maager");
|
||||||
|
|
||||||
_imageTexture = Texture::Builder()
|
_dummyImageTexture = Texture::Builder()
|
||||||
.width(1)
|
.width(1)
|
||||||
.height(1)
|
.height(1)
|
||||||
.levels(0x01)
|
.levels(0x01)
|
||||||
@@ -230,7 +229,7 @@ namespace thermion_filament
|
|||||||
.build(*_engine);
|
.build(*_engine);
|
||||||
_imageMaterial->setDefaultParameter("showImage", 0);
|
_imageMaterial->setDefaultParameter("showImage", 0);
|
||||||
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(1.0f, 1.0f, 1.0f, 0.0f));
|
_imageMaterial->setDefaultParameter("backgroundColor", RgbaType::sRGB, float4(1.0f, 1.0f, 1.0f, 0.0f));
|
||||||
_imageMaterial->setDefaultParameter("image", _imageTexture, _imageSampler);
|
_imageMaterial->setDefaultParameter("image", _dummyImageTexture, _imageSampler);
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
@@ -269,7 +268,6 @@ namespace thermion_filament
|
|||||||
.culling(false)
|
.culling(false)
|
||||||
.build(*_engine, _imageEntity);
|
.build(*_engine, _imageEntity);
|
||||||
_scene->addEntity(_imageEntity);
|
_scene->addEntity(_imageEntity);
|
||||||
Log("Added imageEntity %d", _imageEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilamentViewer::setAntiAliasing(bool msaa, bool fxaa, bool taa)
|
void FilamentViewer::setAntiAliasing(bool msaa, bool fxaa, bool taa)
|
||||||
@@ -444,7 +442,8 @@ namespace thermion_filament
|
|||||||
new ktxreader::Ktx1Bundle(static_cast<const uint8_t *>(rb.data),
|
new ktxreader::Ktx1Bundle(static_cast<const uint8_t *>(rb.data),
|
||||||
static_cast<uint32_t>(rb.size));
|
static_cast<uint32_t>(rb.size));
|
||||||
|
|
||||||
// because the ResourceBuffer will go out of scope before the texture callback is invoked, we need to make a copy to the heap
|
// the ResourceBuffer will go out of scope before the texture callback is invoked
|
||||||
|
// make a copy to the heap
|
||||||
ResourceBuffer *rbCopy = new ResourceBuffer(rb);
|
ResourceBuffer *rbCopy = new ResourceBuffer(rb);
|
||||||
|
|
||||||
std::vector<void *> *callbackData = new std::vector<void *>{(void *)_resourceLoaderWrapper, rbCopy};
|
std::vector<void *> *callbackData = new std::vector<void *>{(void *)_resourceLoaderWrapper, rbCopy};
|
||||||
@@ -550,6 +549,7 @@ namespace thermion_filament
|
|||||||
|
|
||||||
void FilamentViewer::clearBackgroundImage()
|
void FilamentViewer::clearBackgroundImage()
|
||||||
{
|
{
|
||||||
|
_imageMaterial->setDefaultParameter("image", _dummyImageTexture, _imageSampler);
|
||||||
_imageMaterial->setDefaultParameter("showImage", 0);
|
_imageMaterial->setDefaultParameter("showImage", 0);
|
||||||
if (_imageTexture)
|
if (_imageTexture)
|
||||||
{
|
{
|
||||||
@@ -680,22 +680,21 @@ namespace thermion_filament
|
|||||||
|
|
||||||
FilamentViewer::~FilamentViewer()
|
FilamentViewer::~FilamentViewer()
|
||||||
{
|
{
|
||||||
clearEntities();
|
clearLights();
|
||||||
|
destroySwapChain();
|
||||||
|
_engine->destroy(_imageEntity);
|
||||||
|
_engine->destroy(_imageTexture);
|
||||||
|
_engine->destroy(_imageVb);
|
||||||
|
_engine->destroy(_imageIb);
|
||||||
|
_engine->destroy(_imageMaterial);
|
||||||
delete _sceneManager;
|
delete _sceneManager;
|
||||||
|
|
||||||
for (auto it : _lights)
|
|
||||||
{
|
|
||||||
_engine->destroy(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
_engine->destroyCameraComponent(_mainCamera->getEntity());
|
_engine->destroyCameraComponent(_mainCamera->getEntity());
|
||||||
_mainCamera = nullptr;
|
_mainCamera = nullptr;
|
||||||
_engine->destroy(_view);
|
_engine->destroy(_view);
|
||||||
_engine->destroy(_scene);
|
_engine->destroy(_scene);
|
||||||
_engine->destroy(_renderer);
|
_engine->destroy(_renderer);
|
||||||
_engine->destroy(_swapChain);
|
Engine::destroy(&_engine);
|
||||||
|
delete _resourceLoaderWrapper;
|
||||||
Engine::destroy(&_engine); // clears engine*
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Renderer *FilamentViewer::getRenderer() { return _renderer; }
|
Renderer *FilamentViewer::getRenderer() { return _renderer; }
|
||||||
@@ -930,7 +929,6 @@ namespace thermion_filament
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log("Loading skybox from path %s", skyboxPath);
|
Log("Loading skybox from path %s", skyboxPath);
|
||||||
|
|
||||||
ResourceBuffer skyboxBuffer = _resourceLoaderWrapper->load(skyboxPath);
|
ResourceBuffer skyboxBuffer = _resourceLoaderWrapper->load(skyboxPath);
|
||||||
|
|
||||||
// because this will go out of scope before the texture callback is invoked, we need to make a copy of the variable itself (not its contents)
|
// because this will go out of scope before the texture callback is invoked, we need to make a copy of the variable itself (not its contents)
|
||||||
|
|||||||
@@ -93,10 +93,28 @@ namespace thermion_filament
|
|||||||
|
|
||||||
SceneManager::~SceneManager()
|
SceneManager::~SceneManager()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
destroyAll();
|
||||||
|
|
||||||
|
for(int i =0; i < 3; i++) {
|
||||||
|
_engine->destroy(_gizmo[i]);
|
||||||
|
_engine->destroy(_gizmoMaterialInstances[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_engine->destroy(_gizmoMaterial);
|
||||||
_gltfResourceLoader->asyncCancelLoad();
|
_gltfResourceLoader->asyncCancelLoad();
|
||||||
_ubershaderProvider->destroyMaterials();
|
_ubershaderProvider->destroyMaterials();
|
||||||
destroyAll();
|
|
||||||
|
delete _animationComponentManager;
|
||||||
|
delete _collisionComponentManager;
|
||||||
|
delete _ncm;
|
||||||
|
|
||||||
|
delete _gltfResourceLoader;
|
||||||
|
delete _stbDecoder;
|
||||||
|
delete _ktxDecoder;
|
||||||
|
delete _ubershaderProvider;
|
||||||
AssetLoader::destroy(&_assetLoader);
|
AssetLoader::destroy(&_assetLoader);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int SceneManager::getInstanceCount(EntityId entityId)
|
int SceneManager::getInstanceCount(EntityId entityId)
|
||||||
@@ -2045,72 +2063,57 @@ namespace thermion_filament
|
|||||||
|
|
||||||
auto &entityManager = EntityManager::get();
|
auto &entityManager = EntityManager::get();
|
||||||
|
|
||||||
_gizmoY = entityManager.create();
|
_gizmo[1] = entityManager.create();
|
||||||
auto materialY = _gizmoMaterial->createInstance();
|
_gizmoMaterialInstances[1] = _gizmoMaterial->createInstance();
|
||||||
materialY->setParameter("color", math::float3{1.0f, 0.0f, 0.0f});
|
_gizmoMaterialInstances[1]->setParameter("color", math::float3{1.0f, 0.0f, 0.0f});
|
||||||
RenderableManager::Builder(1)
|
RenderableManager::Builder(1)
|
||||||
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
||||||
.material(0, materialY)
|
.material(0, _gizmoMaterialInstances[1])
|
||||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
||||||
ib, 0, indexCount)
|
ib, 0, indexCount)
|
||||||
.culling(false)
|
.culling(false)
|
||||||
.build(*_engine, _gizmoY);
|
.build(*_engine, _gizmo[1]);
|
||||||
|
|
||||||
_gizmoX = entityManager.create();
|
_gizmo[0] = entityManager.create();
|
||||||
auto materialX = _gizmoMaterial->createInstance();
|
_gizmoMaterialInstances[0] = _gizmoMaterial->createInstance();
|
||||||
materialX->setParameter("color", math::float3{0.0f, 1.0f, 0.0f});
|
_gizmoMaterialInstances[0]->setParameter("color", math::float3{0.0f, 1.0f, 0.0f});
|
||||||
auto xTransform = math::mat4f::translation(math::float3{0.0f, 0.05f, -0.05f}) * math::mat4f::rotation(-math::F_PI_2, math::float3{0, 0, 1});
|
auto xTransform = math::mat4f::translation(math::float3{0.0f, 0.05f, -0.05f}) * math::mat4f::rotation(-math::F_PI_2, math::float3{0, 0, 1});
|
||||||
auto *instanceBufferX = InstanceBuffer::Builder(1).localTransforms(&xTransform).build(*_engine);
|
auto *instanceBufferX = InstanceBuffer::Builder(1).localTransforms(&xTransform).build(*_engine);
|
||||||
RenderableManager::Builder(1)
|
RenderableManager::Builder(1)
|
||||||
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
||||||
.instances(1, instanceBufferX)
|
.instances(1, instanceBufferX)
|
||||||
.material(0, materialX)
|
.material(0, _gizmoMaterialInstances[0])
|
||||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
||||||
ib, 0, indexCount)
|
ib, 0, indexCount)
|
||||||
.culling(false)
|
.culling(false)
|
||||||
.build(*_engine, _gizmoX);
|
.build(*_engine, _gizmo[0]);
|
||||||
|
|
||||||
_gizmoZ = entityManager.create();
|
_gizmo[2] = entityManager.create();
|
||||||
auto materialZ = _gizmoMaterial->createInstance();
|
_gizmoMaterialInstances[2] = _gizmoMaterial->createInstance();
|
||||||
materialZ->setParameter("color", math::float3{0.0f, 0.0f, 1.0f});
|
_gizmoMaterialInstances[2]->setParameter("color", math::float3{0.0f, 0.0f, 1.0f});
|
||||||
auto zTransform = math::mat4f::translation(math::float3{0.0f, 0.05f, -0.05f}) * math::mat4f::rotation(3 * math::F_PI_2, math::float3{1, 0, 0});
|
auto zTransform = math::mat4f::translation(math::float3{0.0f, 0.05f, -0.05f}) * math::mat4f::rotation(3 * math::F_PI_2, math::float3{1, 0, 0});
|
||||||
auto *instanceBufferZ = InstanceBuffer::Builder(1).localTransforms(&zTransform).build(*_engine);
|
auto *instanceBufferZ = InstanceBuffer::Builder(1).localTransforms(&zTransform).build(*_engine);
|
||||||
RenderableManager::Builder(1)
|
RenderableManager::Builder(1)
|
||||||
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
.boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
||||||
.instances(1, instanceBufferZ)
|
.instances(1, instanceBufferZ)
|
||||||
.material(0, materialZ)
|
.material(0, _gizmoMaterialInstances[2])
|
||||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
||||||
ib, 0, indexCount)
|
ib, 0, indexCount)
|
||||||
.culling(false)
|
.culling(false)
|
||||||
.build(*_engine, _gizmoZ);
|
.build(*_engine, _gizmo[2]);
|
||||||
|
|
||||||
// auto localTransforms = math::mat4f[3] {
|
|
||||||
// math::mat4f(),
|
|
||||||
// math::mat4f::translation(math::float3 { 0.0f, 0.05f, -0.05f}) * math::mat4f::rotation(3 * math::F_PI_2, math::float3 { 1, 0, 0 }) ,
|
|
||||||
// math::mat4f::translation(math::float3 { 0.0f, 0.05f, -0.05f}) * math::mat4f::rotation(math::F_PI_2, math::float3 { 0, 0, 1 })
|
|
||||||
// };
|
|
||||||
|
|
||||||
// RenderableManager::Builder(1)
|
|
||||||
// .boundingBox({{}, {1.0f, 1.0f, 1.0f}})
|
|
||||||
// .instances(3, instanceBuffer)
|
|
||||||
// .material(0, _gizmoMaterial->getDefaultInstance())
|
|
||||||
// .geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb,
|
|
||||||
// ib, 0, indexCount)
|
|
||||||
// .culling(false)
|
|
||||||
// .build(*_engine, _gizmo);
|
|
||||||
|
|
||||||
auto &rm = _engine->getRenderableManager();
|
auto &rm = _engine->getRenderableManager();
|
||||||
rm.setPriority(rm.getInstance(_gizmoX), 7);
|
rm.setPriority(rm.getInstance(_gizmo[0]), 7);
|
||||||
rm.setPriority(rm.getInstance(_gizmoY), 7);
|
rm.setPriority(rm.getInstance(_gizmo[1]), 7);
|
||||||
rm.setPriority(rm.getInstance(_gizmoZ), 7);
|
rm.setPriority(rm.getInstance(_gizmo[2]), 7);
|
||||||
return Entity::smuggle(_gizmoX);
|
return Entity::smuggle(_gizmo[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SceneManager::getGizmo(EntityId *out)
|
void SceneManager::getGizmo(EntityId *out)
|
||||||
{
|
{
|
||||||
out[0] = Entity::smuggle(_gizmoX);
|
out[0] = Entity::smuggle(_gizmo[0]);
|
||||||
out[1] = Entity::smuggle(_gizmoY);
|
out[1] = Entity::smuggle(_gizmo[1]);
|
||||||
out[2] = Entity::smuggle(_gizmoZ);
|
out[2] = Entity::smuggle(_gizmo[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_filament
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ extern "C"
|
|||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE const void *create_filament_viewer(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
EMSCRIPTEN_KEEPALIVE const void *create_filament_viewer(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||||
{
|
{
|
||||||
auto viewer = (const void *)new FilamentViewer(context, (const ResourceLoaderWrapperImpl *const)loader, platform, uberArchivePath);
|
const auto * loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper*)loader);
|
||||||
|
auto viewer = (const void *)new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
||||||
return viewer;
|
return viewer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,9 +13,6 @@ extern "C"
|
|||||||
{
|
{
|
||||||
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
|
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
|
||||||
}
|
}
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ThermionDartFFIApi.h"
|
#include "ThermionDartFFIApi.h"
|
||||||
@@ -39,19 +36,27 @@ public:
|
|||||||
explicit RenderLoop()
|
explicit RenderLoop()
|
||||||
{
|
{
|
||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
pthread_attr_t attr;
|
pthread_attr_t attr;
|
||||||
pthread_attr_init(&attr);
|
pthread_attr_init(&attr);
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
|
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
|
||||||
#endif
|
|
||||||
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
|
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
|
||||||
|
#else
|
||||||
|
t = new std::thread([this]() {
|
||||||
|
start();
|
||||||
|
});
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
~RenderLoop()
|
~RenderLoop()
|
||||||
{
|
{
|
||||||
_stop = true;
|
_stop = true;
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
pthread_join(t, NULL);
|
pthread_join(t, NULL);
|
||||||
|
#else
|
||||||
|
t->join();
|
||||||
|
#endif
|
||||||
|
Log("Render loop killed");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mainLoop(void* arg) {
|
static void mainLoop(void* arg) {
|
||||||
@@ -103,48 +108,47 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void createViewer(void *const context, void *const platform,
|
void createViewer(void *const context,
|
||||||
|
void *const platform,
|
||||||
const char *uberArchivePath,
|
const char *uberArchivePath,
|
||||||
const ResourceLoaderWrapperImpl *const loader,
|
const ResourceLoaderWrapper *const loader,
|
||||||
void (*renderCallback)(void *),
|
void (*renderCallback)(void *),
|
||||||
void *const owner,
|
void *const owner,
|
||||||
void (*callback)(void *const))
|
void (*callback)(void *const))
|
||||||
{
|
{
|
||||||
_renderCallback = renderCallback;
|
_renderCallback = renderCallback;
|
||||||
_renderCallbackOwner = owner;
|
_renderCallbackOwner = owner;
|
||||||
std::packaged_task<FilamentViewer *()> lambda([=]() mutable
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
{
|
{
|
||||||
FilamentViewer* viewer = nullptr;
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
_context = thermion_dart_web_create_gl_context();
|
_context = thermion_dart_web_create_gl_context();
|
||||||
|
|
||||||
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
|
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
|
||||||
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
||||||
std::cout << "Failed to make context current." << std::endl;
|
std::cout << "Failed to make context current." << std::endl;
|
||||||
return viewer;
|
return;
|
||||||
}
|
}
|
||||||
glClearColor(0.0, 0.5, 0.5, 1.0);
|
glClearColor(0.0, 0.5, 0.5, 1.0);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
// emscripten_webgl_commit_frame();
|
// emscripten_webgl_commit_frame();
|
||||||
|
|
||||||
viewer = (FilamentViewer*) create_filament_viewer((void* const) _context, loader, platform, uberArchivePath);
|
_viewer = (FilamentViewer*) create_filament_viewer((void* const) _context, loader, platform, uberArchivePath);
|
||||||
MAIN_THREAD_EM_ASM({
|
MAIN_THREAD_EM_ASM({
|
||||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
moduleArg.dartFilamentResolveCallback($0, $1);
|
||||||
}, callback, viewer);
|
}, callback, _viewer);
|
||||||
#else
|
#else
|
||||||
viewer = (FilamentViewer*)create_filament_viewer(context, loader, platform, uberArchivePath);
|
_viewer = (FilamentViewer*)create_filament_viewer(context, loader, platform, uberArchivePath);
|
||||||
callback(viewer);
|
callback(_viewer);
|
||||||
#endif
|
#endif
|
||||||
_viewer = viewer;
|
});
|
||||||
return viewer; });
|
|
||||||
auto fut = add_task(lambda);
|
auto fut = add_task(lambda);
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroyViewer(FilamentViewer* viewer)
|
void destroyViewer(FilamentViewer* viewer)
|
||||||
{
|
{
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
std::packaged_task<void()> lambda([=]() mutable {
|
||||||
{
|
|
||||||
_rendering = false;
|
_rendering = false;
|
||||||
|
_viewer = nullptr;
|
||||||
destroy_filament_viewer(viewer);
|
destroy_filament_viewer(viewer);
|
||||||
});
|
});
|
||||||
auto fut = add_task(lambda);
|
auto fut = add_task(lambda);
|
||||||
@@ -210,13 +214,17 @@ public:
|
|||||||
std::mutex _access;
|
std::mutex _access;
|
||||||
void (*_renderCallback)(void *const) = nullptr;
|
void (*_renderCallback)(void *const) = nullptr;
|
||||||
void *_renderCallbackOwner = nullptr;
|
void *_renderCallbackOwner = nullptr;
|
||||||
pthread_t t;
|
|
||||||
|
|
||||||
std::condition_variable _cond;
|
std::condition_variable _cond;
|
||||||
std::deque<std::function<void()>> _tasks;
|
std::deque<std::function<void()>> _tasks;
|
||||||
FilamentViewer* _viewer = nullptr;
|
FilamentViewer* _viewer = nullptr;
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
|
pthread_t t;
|
||||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
|
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
|
||||||
int _frameNum = 0;
|
int _frameNum = 0;
|
||||||
|
#else
|
||||||
|
std::thread *t = nullptr;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -237,13 +245,15 @@ extern "C"
|
|||||||
{
|
{
|
||||||
_rl = new RenderLoop();
|
_rl = new RenderLoop();
|
||||||
}
|
}
|
||||||
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapperImpl *const)loader,
|
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapper *const)loader,
|
||||||
renderCallback, renderCallbackOwner, callback);
|
renderCallback, renderCallbackOwner, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer)
|
||||||
{
|
{
|
||||||
_rl->destroyViewer((FilamentViewer*)viewer);
|
_rl->destroyViewer((FilamentViewer*)viewer);
|
||||||
|
delete _rl;
|
||||||
|
_rl = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer,
|
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY build/out)
|
|||||||
|
|
||||||
add_executable(${MODULE_NAME}
|
add_executable(${MODULE_NAME}
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/SceneManager.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/SceneManager.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionViewerFFI.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/FilamentViewer.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionDartApi.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionDartApi.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionDartFFIApi.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/ThermionDartFFIApi.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/StreamBufferAdapter.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/StreamBufferAdapter.cpp"
|
||||||
@@ -221,10 +221,10 @@ target_link_libraries(${MODULE_NAME}
|
|||||||
tinyexr
|
tinyexr
|
||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET ${MODULE_NAME} POST_BUILD
|
# add_custom_command(TARGET ${MODULE_NAME} POST_BUILD
|
||||||
COMMAND dart --enable-experiment=native-assets run ffigen --config ffigen/web.yaml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
# COMMAND dart --enable-experiment=native-assets run ffigen --config ffigen/web.yaml WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../../
|
||||||
COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart "-DTO_REPLACE=symbol: '" "-DREPLACEMENT=symbol: '_" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake
|
# COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/../../lib/thermion_dart/compatibility/web/thermion_dart.g.dart "-DTO_REPLACE=symbol: '" "-DREPLACEMENT=symbol: '_" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake
|
||||||
# COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js "-DTO_REPLACE=var moduleRtn" "-DREPLACEMENT=var moduleRtn\;GLctx=moduleArg.ctx" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake
|
# # COMMAND ${CMAKE_COMMAND} -DINPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js -DOUTPUTFILE=${CMAKE_CURRENT_SOURCE_DIR}/build/build/out/thermion_dart.js "-DTO_REPLACE=var moduleRtn" "-DREPLACEMENT=var moduleRtn\;GLctx=moduleArg.ctx" -P ${CMAKE_CURRENT_SOURCE_DIR}/replace_in_file.cmake
|
||||||
VERBATIM
|
# VERBATIM
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ extern "C"
|
|||||||
attr.stencil = EM_FALSE;
|
attr.stencil = EM_FALSE;
|
||||||
attr.antialias = EM_FALSE;
|
attr.antialias = EM_FALSE;
|
||||||
attr.explicitSwapControl = EM_FALSE;
|
attr.explicitSwapControl = EM_FALSE;
|
||||||
attr.preserveDrawingBuffer = EM_FALSE;
|
attr.preserveDrawingBuffer = EM_TRUE;
|
||||||
attr.proxyContextToMainThread = EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW;
|
attr.proxyContextToMainThread = EMSCRIPTEN_WEBGL_CONTEXT_PROXY_DISALLOW;
|
||||||
attr.enableExtensionsByDefault = EM_TRUE;
|
attr.enableExtensionsByDefault = EM_TRUE;
|
||||||
attr.renderViaOffscreenBackBuffer = EM_FALSE;
|
attr.renderViaOffscreenBackBuffer = EM_FALSE;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: thermion_dart
|
name: thermion_dart
|
||||||
description: 3D rendering toolkit for Dart.
|
description: 3D rendering toolkit for Dart.
|
||||||
version: 0.0.4
|
version: 0.1.1+2
|
||||||
homepage: https://docs.page/nmfisher/thermion
|
homepage: https://docs.page/nmfisher/thermion
|
||||||
repository: https://github.com/nmfisher/thermion
|
repository: https://github.com/nmfisher/thermion
|
||||||
|
|
||||||
@@ -15,6 +15,7 @@ dependencies:
|
|||||||
native_toolchain_c: ^0.4.2
|
native_toolchain_c: ^0.4.2
|
||||||
archive: ^3.6.1
|
archive: ^3.6.1
|
||||||
web: ^0.5.1
|
web: ^0.5.1
|
||||||
|
logging: ^1.2.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
ffigen: ^11.0.0
|
ffigen: ^11.0.0
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import 'dart:ffi';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:thermion_dart/thermion_dart/swift/swift_bindings.g.dart';
|
import 'package:thermion_dart/thermion_dart/swift/swift_bindings.g.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/thermion_viewer_ffi.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/utils/dart_resources.dart';
|
import 'package:thermion_dart/thermion_dart/utils/dart_resources.dart';
|
||||||
import 'package:ffi/ffi.dart';
|
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/compatibility.dart';
|
import 'package:thermion_dart/thermion_dart/compatibility/compatibility.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
../thermion_dart
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
## 0.1.1+7
|
||||||
|
|
||||||
|
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
|
||||||
|
|
||||||
|
## 0.1.1-dev.0+7
|
||||||
|
|
||||||
|
- **FIX**: add ResourceBuffer header directly to Windows build so I don't have to fiddle around getting the CMake path right.
|
||||||
|
|
||||||
|
## 0.1.1+6
|
||||||
|
|
||||||
|
- **DOCS**: update with links to playground.
|
||||||
|
|
||||||
|
## 0.1.1+5
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.1+4
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.1+3
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.1+2
|
||||||
|
|
||||||
|
- **FIX**: update Flutter example project to use new API.
|
||||||
|
- **FIX**: add logging dependency to thermion_flutter.
|
||||||
|
|
||||||
|
## 0.1.1+1
|
||||||
|
|
||||||
|
- **REFACTOR**: export ThermionViewerWasm for web and hide FFI/WASM version.
|
||||||
|
- **FIX**: catch exception if gizmo unavailable in ThermionGestureDestectorDesktop.
|
||||||
|
|
||||||
|
## 0.1.0
|
||||||
|
* [ThermionFlutterPlugin] is now static and [dispose] has been removed. Call [createViewer] to obtain an instance of [ThermionViewer]. If you need to release all resources, call [dispose] on [ThermionViewer]
|
||||||
|
* Fixed memory leaks
|
||||||
|
|
||||||
|
## 0.0.4
|
||||||
|
* First release of Dart-only package
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://docs.page/nmfisher/flutter_filament/quickstart">Quickstart (Flutter)</a> •
|
<a href="https://docs.page/nmfisher/flutter_filament/quickstart">Quickstart (Flutter)</a> •
|
||||||
<a href="https://docs.page/nmfisher/flutter_filament">Documentation</a> •
|
<a href="https://docs.page/nmfisher/flutter_filament">Documentation</a> •
|
||||||
<a href="https://github.com/nmfisher/thermion/docs/examples/">Showcase</a> •
|
<a href="https://github.com/nmfisher/thermion/docs/examples/">Showcase</a> •
|
||||||
|
<a href="https://dartpad.thermion.dev/">Playground</a> •
|
||||||
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ class RenderCallbackImpl(plugin:ThermionFlutterPlugin) : RenderCallback {
|
|||||||
class ThermionFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, LoadFilamentResourceFromOwner, FreeFilamentResourceFromOwner {
|
class ThermionFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware, LoadFilamentResourceFromOwner, FreeFilamentResourceFromOwner {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val CHANNEL_NAME = "app.polyvox.filament/event"
|
const val CHANNEL_NAME = "dev.thermion.flutter/event"
|
||||||
const val TAG = "FilamentPlugin"
|
const val TAG = "FilamentPlugin"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.h"
|
||||||
|
|
||||||
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
|
void *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
|
||||||
{
|
{
|
||||||
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
|
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
|
||||||
|
rlw->loadResource = NULL;
|
||||||
|
rlw->freeResource = NULL;
|
||||||
|
rlw->loadToOut = NULL;
|
||||||
rlw->loadFromOwner = loadFn;
|
rlw->loadFromOwner = loadFn;
|
||||||
rlw->freeFromOwner = freeFn;
|
rlw->freeFromOwner = freeFn;
|
||||||
rlw->owner = owner;
|
rlw->owner = owner;
|
||||||
|
|||||||
@@ -127,7 +127,7 @@ public class SwiftThermionFlutterPlugin: NSObject, FlutterPlugin {
|
|||||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
let _messenger = registrar.messenger();
|
let _messenger = registrar.messenger();
|
||||||
messenger = _messenger;
|
messenger = _messenger;
|
||||||
let channel = FlutterMethodChannel(name: "app.polyvox.filament/event", binaryMessenger: _messenger)
|
let channel = FlutterMethodChannel(name: "dev.thermion.flutter/event", binaryMessenger: _messenger)
|
||||||
let instance = SwiftThermionFlutterPlugin(textureRegistry: registrar.textures(), registrar:registrar)
|
let instance = SwiftThermionFlutterPlugin(textureRegistry: registrar.textures(), registrar:registrar)
|
||||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef RESOURCE_BUFFER_H
|
||||||
|
#define RESOURCE_BUFFER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// A ResourceBuffer is a unified interface for working with
|
||||||
|
// binary assets across various platforms.
|
||||||
|
// This is simply:
|
||||||
|
// 1) a pointer to some data
|
||||||
|
// 2) the length of the data
|
||||||
|
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
|
||||||
|
//
|
||||||
|
typedef struct ResourceBuffer
|
||||||
|
{
|
||||||
|
const void *const data;
|
||||||
|
const int32_t size;
|
||||||
|
const int32_t id;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
ResourceBuffer(void *const data, int32_t size, int32_t id) : data(data), size(size), id(id) {}
|
||||||
|
#endif
|
||||||
|
} ResourceBuffer;
|
||||||
|
|
||||||
|
typedef void (*LoadFilamentResourceIntoOutPointer)(const char *uri, ResourceBuffer *out);
|
||||||
|
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
|
||||||
|
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
|
||||||
|
typedef void (*FreeFilamentResource)(ResourceBuffer);
|
||||||
|
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
|
||||||
|
|
||||||
|
typedef struct ResourceLoaderWrapper
|
||||||
|
{
|
||||||
|
LoadFilamentResource loadResource;
|
||||||
|
FreeFilamentResource freeResource;
|
||||||
|
LoadFilamentResourceFromOwner loadFromOwner;
|
||||||
|
FreeFilamentResourceFromOwner freeFromOwner;
|
||||||
|
void *owner;
|
||||||
|
LoadFilamentResourceIntoOutPointer loadToOut;
|
||||||
|
} ResourceLoaderWrapper;
|
||||||
|
|
||||||
|
void *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
#ifndef RESOURCE_BUFFER_H
|
|
||||||
#define RESOURCE_BUFFER_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
//
|
|
||||||
// A ResourceBuffer is a unified interface for working with
|
|
||||||
// binary assets across various platforms.
|
|
||||||
// This is simply:
|
|
||||||
// 1) a pointer to some data
|
|
||||||
// 2) the length of the data
|
|
||||||
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
|
|
||||||
//
|
|
||||||
struct ResourceBuffer
|
|
||||||
{
|
|
||||||
const void *const data;
|
|
||||||
const int32_t size;
|
|
||||||
const int32_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ResourceBuffer ResourceBuffer;
|
|
||||||
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
|
|
||||||
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
|
|
||||||
typedef void (*FreeFilamentResource)(ResourceBuffer);
|
|
||||||
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
|
|
||||||
|
|
||||||
struct ResourceLoaderWrapper
|
|
||||||
{
|
|
||||||
LoadFilamentResource loadResource;
|
|
||||||
FreeFilamentResource freeResource;
|
|
||||||
LoadFilamentResourceFromOwner loadFromOwner;
|
|
||||||
FreeFilamentResourceFromOwner freeFromOwner;
|
|
||||||
void *owner;
|
|
||||||
};
|
|
||||||
typedef struct ResourceLoaderWrapper ResourceLoaderWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
|
|
||||||
namespace thermion_filament {
|
|
||||||
|
|
||||||
struct ResourceLoaderWrapperImpl : public ResourceLoaderWrapper
|
|
||||||
{
|
|
||||||
|
|
||||||
ResourceLoaderWrapperImpl(LoadFilamentResource loader, FreeFilamentResource freeResource)
|
|
||||||
{
|
|
||||||
loadFromOwner = nullptr;
|
|
||||||
freeFromOwner = nullptr;
|
|
||||||
loadResource = loader;
|
|
||||||
freeResource = freeResource;
|
|
||||||
owner = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceLoaderWrapperImpl(LoadFilamentResourceFromOwner loader, FreeFilamentResourceFromOwner freeResource, void * owner)
|
|
||||||
{
|
|
||||||
loadResource = nullptr;
|
|
||||||
freeResource = nullptr;
|
|
||||||
loadFromOwner = loader;
|
|
||||||
freeFromOwner = freeResource;
|
|
||||||
owner = owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceBuffer load(const char *uri) const
|
|
||||||
{
|
|
||||||
if (loadFromOwner)
|
|
||||||
{
|
|
||||||
auto rb = loadFromOwner(uri, owner);
|
|
||||||
return rb;
|
|
||||||
}
|
|
||||||
auto rb = loadResource(uri);
|
|
||||||
return rb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(ResourceBuffer rb) const
|
|
||||||
{
|
|
||||||
if (freeFromOwner)
|
|
||||||
{
|
|
||||||
freeFromOwner(rb, owner);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
freeResource(rb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.h"
|
||||||
|
|
||||||
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner);
|
void *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner);
|
||||||
|
|
||||||
// ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
|
// ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
|
||||||
// {
|
// {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ A new flutter plugin project.
|
|||||||
s.license = { :file => '../LICENSE' }
|
s.license = { :file => '../LICENSE' }
|
||||||
s.author = { 'Your Company' => 'email@example.com' }
|
s.author = { 'Your Company' => 'email@example.com' }
|
||||||
s.source = { :path => '.' }
|
s.source = { :path => '.' }
|
||||||
s.source_files = 'Classes/*', 'include/SwiftThermionFlutterPlugin-Bridging-Header.h','include/ResourceBuffer.hpp', 'src/ResourceBuffer.c'
|
s.source_files = 'Classes/*', 'include/SwiftThermionFlutterPlugin-Bridging-Header.h','include/ResourceBuffer.h', 'src/ResourceBuffer.c'
|
||||||
s.public_header_files = 'include/SwiftThermionFlutterPlugin-Bridging-Header.h', 'include/ResourceBuffer.hpp'
|
s.public_header_files = 'include/SwiftThermionFlutterPlugin-Bridging-Header.h', 'include/ResourceBuffer.h'
|
||||||
s.dependency 'Flutter'
|
s.dependency 'Flutter'
|
||||||
s.platform = :ios, '13.0'
|
s.platform = :ios, '13.0'
|
||||||
s.static_framework = true
|
s.static_framework = true
|
||||||
|
|||||||
@@ -1,103 +1,100 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:ui';
|
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Handles all platform-specific initialization work necessary to create a
|
/// Handles all platform-specific initialization to create a backing rendering
|
||||||
/// backing rendering surface in a Flutter application.
|
/// surface in a Flutter application and lifecycle listeners to pause rendering
|
||||||
/// Instantiates/wraps a [ThermionViewer],
|
/// when the app is inactive or in the background.
|
||||||
|
/// Call [createViewer] to create an instance of [ThermionViewer].
|
||||||
|
/// This is a lightweight singleton that
|
||||||
///
|
///
|
||||||
class ThermionFlutterPlugin {
|
class ThermionFlutterPlugin {
|
||||||
ThermionViewer get _viewer => ThermionFlutterPlatform.instance.viewer;
|
|
||||||
|
ThermionFlutterPlugin._();
|
||||||
|
|
||||||
bool _wasRenderingOnInactive = false;
|
static AppLifecycleListener? _appLifecycleListener;
|
||||||
|
|
||||||
void _handleStateChange(AppLifecycleState state) async {
|
static bool _initializing = false;
|
||||||
await initialized;
|
|
||||||
|
static ThermionViewer? _viewer;
|
||||||
|
|
||||||
|
static bool _wasRenderingOnInactive = false;
|
||||||
|
|
||||||
|
static void _handleStateChange(AppLifecycleState state) async {
|
||||||
|
if (_viewer == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _viewer!.initialized;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case AppLifecycleState.detached:
|
case AppLifecycleState.detached:
|
||||||
print("Detached");
|
|
||||||
if (!_wasRenderingOnInactive) {
|
if (!_wasRenderingOnInactive) {
|
||||||
_wasRenderingOnInactive = _viewer.rendering;
|
_wasRenderingOnInactive = _viewer!.rendering;
|
||||||
}
|
}
|
||||||
await _viewer.setRendering(false);
|
await _viewer!.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.hidden:
|
case AppLifecycleState.hidden:
|
||||||
print("Hidden");
|
|
||||||
if (!_wasRenderingOnInactive) {
|
if (!_wasRenderingOnInactive) {
|
||||||
_wasRenderingOnInactive = _viewer.rendering;
|
_wasRenderingOnInactive = _viewer!.rendering;
|
||||||
}
|
}
|
||||||
await _viewer.setRendering(false);
|
await _viewer!.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.inactive:
|
case AppLifecycleState.inactive:
|
||||||
print("Inactive");
|
|
||||||
if (!_wasRenderingOnInactive) {
|
if (!_wasRenderingOnInactive) {
|
||||||
_wasRenderingOnInactive = _viewer.rendering;
|
_wasRenderingOnInactive = _viewer!.rendering;
|
||||||
}
|
}
|
||||||
// on Windows in particular, restoring a window after minimizing stalls the renderer (and the whole application) for a considerable length of time.
|
// on Windows in particular, restoring a window after minimizing stalls the renderer (and the whole application) for a considerable length of time.
|
||||||
// disabling rendering on minimize seems to fix the issue (so I wonder if there's some kind of command buffer that's filling up while the window is minimized).
|
// disabling rendering on minimize seems to fix the issue (so I wonder if there's some kind of command buffer that's filling up while the window is minimized).
|
||||||
await _viewer.setRendering(false);
|
await _viewer!.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.paused:
|
case AppLifecycleState.paused:
|
||||||
print("Paused");
|
|
||||||
if (!_wasRenderingOnInactive) {
|
if (!_wasRenderingOnInactive) {
|
||||||
_wasRenderingOnInactive = _viewer.rendering;
|
_wasRenderingOnInactive = _viewer!.rendering;
|
||||||
}
|
}
|
||||||
await _viewer.setRendering(false);
|
await _viewer!.setRendering(false);
|
||||||
break;
|
break;
|
||||||
case AppLifecycleState.resumed:
|
case AppLifecycleState.resumed:
|
||||||
print("Resumed");
|
await _viewer!.setRendering(_wasRenderingOnInactive);
|
||||||
await _viewer.setRendering(_wasRenderingOnInactive);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppLifecycleListener? _appLifecycleListener;
|
static Future<ThermionViewer> createViewer({String? uberArchivePath}) async {
|
||||||
|
if (_initializing) {
|
||||||
final _initialized = Completer<bool>();
|
throw Exception("Existing call to createViewer has not completed.");
|
||||||
Future<bool> get initialized => _initialized.future;
|
|
||||||
|
|
||||||
bool _initializing = false;
|
|
||||||
|
|
||||||
Future<ThermionViewer> initialize({String? uberArchivePath}) async {
|
|
||||||
_initializing = true;
|
|
||||||
if (_initialized.isCompleted) {
|
|
||||||
return ThermionFlutterPlatform.instance.viewer;
|
|
||||||
}
|
}
|
||||||
await ThermionFlutterPlatform.instance
|
_initializing = true;
|
||||||
.initialize(uberArchivePath: uberArchivePath);
|
_viewer = await ThermionFlutterPlatform.instance
|
||||||
|
.createViewer(uberArchivePath: uberArchivePath);
|
||||||
_appLifecycleListener = AppLifecycleListener(
|
_appLifecycleListener = AppLifecycleListener(
|
||||||
onStateChange: _handleStateChange,
|
onStateChange: _handleStateChange,
|
||||||
);
|
);
|
||||||
_viewer.initialized;
|
_viewer!.onDispose(() async {
|
||||||
_initialized.complete(true);
|
_viewer = null;
|
||||||
|
_appLifecycleListener?.dispose();
|
||||||
|
_appLifecycleListener = null;
|
||||||
|
});
|
||||||
_initializing = false;
|
_initializing = false;
|
||||||
return ThermionFlutterPlatform.instance.viewer;
|
return _viewer!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<ThermionFlutterTexture?> createTexture(
|
static Future<ThermionFlutterTexture?> createTexture(
|
||||||
int width, int height, int offsetLeft, int offsetRight) async {
|
int width, int height, int offsetLeft, int offsetRight) async {
|
||||||
return ThermionFlutterPlatform.instance
|
return ThermionFlutterPlatform.instance
|
||||||
.createTexture(width, height, offsetLeft, offsetRight);
|
.createTexture(width, height, offsetLeft, offsetRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future destroyTexture(ThermionFlutterTexture texture) async {
|
static Future destroyTexture(ThermionFlutterTexture texture) async {
|
||||||
return ThermionFlutterPlatform.instance.destroyTexture(texture);
|
return ThermionFlutterPlatform.instance.destroyTexture(texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ThermionFlutterTexture?> resizeTexture(ThermionFlutterTexture texture,
|
static Future<ThermionFlutterTexture?> resizeTexture(ThermionFlutterTexture texture,
|
||||||
int width, int height, int offsetLeft, int offsetRight) async {
|
int width, int height, int offsetLeft, int offsetRight) async {
|
||||||
return ThermionFlutterPlatform.instance
|
return ThermionFlutterPlatform.instance
|
||||||
.resizeTexture(texture, width, height, offsetLeft, offsetRight);
|
.resizeTexture(texture, width, height, offsetLeft, offsetRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dispose() {
|
|
||||||
ThermionFlutterPlatform.instance.dispose();
|
|
||||||
_appLifecycleListener?.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,15 +3,15 @@ import 'dart:io';
|
|||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'filament_gesture_detector_desktop.dart';
|
import 'thermion_gesture_detector_desktop.dart';
|
||||||
import 'filament_gesture_detector_mobile.dart';
|
import 'thermion_gesture_detector_mobile.dart';
|
||||||
|
|
||||||
enum GestureType { rotateCamera, panCamera, panBackground }
|
enum GestureType { rotateCamera, panCamera, panBackground }
|
||||||
|
|
||||||
///
|
///
|
||||||
/// A widget that translates finger/mouse gestures to zoom/pan/rotate actions.
|
/// A widget that translates finger/mouse gestures to zoom/pan/rotate actions.
|
||||||
///
|
///
|
||||||
class FilamentGestureDetector extends StatelessWidget {
|
class ThermionGestureDetector extends StatelessWidget {
|
||||||
///
|
///
|
||||||
/// The content to display below the gesture detector/listener widget.
|
/// The content to display below the gesture detector/listener widget.
|
||||||
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
||||||
@@ -45,7 +45,7 @@ class FilamentGestureDetector extends StatelessWidget {
|
|||||||
final void Function(ScaleUpdateDetails)? onScaleUpdate;
|
final void Function(ScaleUpdateDetails)? onScaleUpdate;
|
||||||
final void Function(ScaleEndDetails)? onScaleEnd;
|
final void Function(ScaleEndDetails)? onScaleEnd;
|
||||||
|
|
||||||
const FilamentGestureDetector(
|
const ThermionGestureDetector(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
this.child,
|
this.child,
|
||||||
@@ -68,7 +68,7 @@ class FilamentGestureDetector extends StatelessWidget {
|
|||||||
if (kIsWeb || Platform.isLinux ||
|
if (kIsWeb || Platform.isLinux ||
|
||||||
Platform.isWindows ||
|
Platform.isWindows ||
|
||||||
Platform.isMacOS) {
|
Platform.isMacOS) {
|
||||||
return FilamentGestureDetectorDesktop(
|
return ThermionGestureDetectorDesktop(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: child,
|
child: child,
|
||||||
showControlOverlay: showControlOverlay,
|
showControlOverlay: showControlOverlay,
|
||||||
@@ -76,7 +76,7 @@ class FilamentGestureDetector extends StatelessWidget {
|
|||||||
enablePicking: enablePicking,
|
enablePicking: enablePicking,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return FilamentGestureDetectorMobile(
|
return ThermionGestureDetectorMobile(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
child: child,
|
child: child,
|
||||||
showControlOverlay: showControlOverlay,
|
showControlOverlay: showControlOverlay,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
|
|||||||
///
|
///
|
||||||
/// A widget that translates finger/mouse gestures to zoom/pan/rotate actions.
|
/// A widget that translates finger/mouse gestures to zoom/pan/rotate actions.
|
||||||
///
|
///
|
||||||
class FilamentGestureDetectorDesktop extends StatefulWidget {
|
class ThermionGestureDetectorDesktop extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// The content to display below the gesture detector/listener widget.
|
/// The content to display below the gesture detector/listener widget.
|
||||||
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
||||||
@@ -37,7 +37,7 @@ class FilamentGestureDetectorDesktop extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
final bool enablePicking;
|
final bool enablePicking;
|
||||||
|
|
||||||
const FilamentGestureDetectorDesktop(
|
const ThermionGestureDetectorDesktop(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
this.child,
|
this.child,
|
||||||
@@ -47,12 +47,13 @@ class FilamentGestureDetectorDesktop extends StatefulWidget {
|
|||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _FilamentGestureDetectorDesktopState();
|
State<StatefulWidget> createState() => _ThermionGestureDetectorDesktopState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FilamentGestureDetectorDesktopState
|
class _ThermionGestureDetectorDesktopState
|
||||||
extends State<FilamentGestureDetectorDesktop> {
|
extends State<ThermionGestureDetectorDesktop> {
|
||||||
///
|
final _logger = Logger("_ThermionGestureDetectorDesktopState");
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
// ignore: unused_field
|
// ignore: unused_field
|
||||||
@@ -65,11 +66,16 @@ class _FilamentGestureDetectorDesktopState
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_gizmo = widget.controller.gizmo;
|
try {
|
||||||
|
_gizmo = widget.controller.gizmo;
|
||||||
|
} catch (err) {
|
||||||
|
_logger.warning(
|
||||||
|
"Failed to get gizmo. If you are running on WASM, this is expected");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(FilamentGestureDetectorDesktop oldWidget) {
|
void didUpdateWidget(ThermionGestureDetectorDesktop oldWidget) {
|
||||||
if (widget.showControlOverlay != oldWidget.showControlOverlay ||
|
if (widget.showControlOverlay != oldWidget.showControlOverlay ||
|
||||||
widget.enableCamera != oldWidget.enableCamera ||
|
widget.enableCamera != oldWidget.enableCamera ||
|
||||||
widget.enablePicking != oldWidget.enablePicking) {
|
widget.enablePicking != oldWidget.enablePicking) {
|
||||||
@@ -7,7 +7,7 @@ enum GestureType { rotateCamera, panCamera, panBackground }
|
|||||||
///
|
///
|
||||||
/// A widget that translates finger/mouse gestures to zoom/pan/rotate actions.
|
/// A widget that translates finger/mouse gestures to zoom/pan/rotate actions.
|
||||||
///
|
///
|
||||||
class FilamentGestureDetectorMobile extends StatefulWidget {
|
class ThermionGestureDetectorMobile extends StatefulWidget {
|
||||||
///
|
///
|
||||||
/// The content to display below the gesture detector/listener widget.
|
/// The content to display below the gesture detector/listener widget.
|
||||||
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
/// This will usually be a ThermionWidget (so you can navigate by directly interacting with the viewport), but this is not necessary.
|
||||||
@@ -43,7 +43,7 @@ class FilamentGestureDetectorMobile extends StatefulWidget {
|
|||||||
final void Function(ScaleUpdateDetails)? onScaleUpdate;
|
final void Function(ScaleUpdateDetails)? onScaleUpdate;
|
||||||
final void Function(ScaleEndDetails)? onScaleEnd;
|
final void Function(ScaleEndDetails)? onScaleEnd;
|
||||||
|
|
||||||
const FilamentGestureDetectorMobile(
|
const ThermionGestureDetectorMobile(
|
||||||
{Key? key,
|
{Key? key,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
this.child,
|
this.child,
|
||||||
@@ -57,11 +57,11 @@ class FilamentGestureDetectorMobile extends StatefulWidget {
|
|||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<StatefulWidget> createState() => _FilamentGestureDetectorMobileState();
|
State<StatefulWidget> createState() => _ThermionGestureDetectorMobileState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FilamentGestureDetectorMobileState
|
class _ThermionGestureDetectorMobileState
|
||||||
extends State<FilamentGestureDetectorMobile> {
|
extends State<ThermionGestureDetectorMobile> {
|
||||||
GestureType gestureType = GestureType.panCamera;
|
GestureType gestureType = GestureType.panCamera;
|
||||||
|
|
||||||
final _icons = {
|
final _icons = {
|
||||||
@@ -116,7 +116,7 @@ class _FilamentGestureDetectorMobileState
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(FilamentGestureDetectorMobile oldWidget) {
|
void didUpdateWidget(ThermionGestureDetectorMobile oldWidget) {
|
||||||
if (widget.showControlOverlay != oldWidget.showControlOverlay ||
|
if (widget.showControlOverlay != oldWidget.showControlOverlay ||
|
||||||
widget.enableCamera != oldWidget.enableCamera ||
|
widget.enableCamera != oldWidget.enableCamera ||
|
||||||
widget.enablePicking != oldWidget.enablePicking) {
|
widget.enablePicking != oldWidget.enablePicking) {
|
||||||
@@ -9,7 +9,7 @@ import 'package:thermion_flutter/thermion_flutter.dart';
|
|||||||
import 'resize_observer.dart';
|
import 'resize_observer.dart';
|
||||||
|
|
||||||
class ThermionWidget extends StatefulWidget {
|
class ThermionWidget extends StatefulWidget {
|
||||||
final ThermionFlutterPlugin plugin;
|
final ThermionViewer viewer;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// The content to render before the texture widget is available.
|
/// The content to render before the texture widget is available.
|
||||||
@@ -17,7 +17,7 @@ class ThermionWidget extends StatefulWidget {
|
|||||||
///
|
///
|
||||||
final Widget? initial;
|
final Widget? initial;
|
||||||
|
|
||||||
const ThermionWidget({Key? key, this.initial, required this.plugin})
|
const ThermionWidget({Key? key, this.initial, required this.viewer})
|
||||||
: super(key: key);
|
: super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -30,12 +30,22 @@ class _ThermionWidgetState extends State<ThermionWidget> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
await widget.plugin.initialized;
|
await widget.viewer.initialized;
|
||||||
|
widget.viewer.onDispose(() async {
|
||||||
|
if (_texture != null) {
|
||||||
|
var texture = _texture;
|
||||||
|
_texture = null;
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
await ThermionFlutterPlugin.destroyTexture(texture!);
|
||||||
|
}
|
||||||
|
});
|
||||||
var dpr = MediaQuery.of(context).devicePixelRatio;
|
var dpr = MediaQuery.of(context).devicePixelRatio;
|
||||||
var size = ((context.findRenderObject()) as RenderBox).size;
|
var size = ((context.findRenderObject()) as RenderBox).size;
|
||||||
var width = (dpr * size.width).ceil();
|
var width = (dpr * size.width).ceil();
|
||||||
var height = (dpr * size.height).ceil();
|
var height = (dpr * size.height).ceil();
|
||||||
_texture = await widget.plugin.createTexture(width, height, 0, 0);
|
_texture = await ThermionFlutterPlugin.createTexture(width, height, 0, 0);
|
||||||
|
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@@ -50,18 +60,20 @@ class _ThermionWidgetState extends State<ThermionWidget> {
|
|||||||
Future _resizeTexture(Size newSize) async {
|
Future _resizeTexture(Size newSize) async {
|
||||||
_resizeTimer?.cancel();
|
_resizeTimer?.cancel();
|
||||||
_resizeTimer = Timer(Duration(milliseconds: 500), () async {
|
_resizeTimer = Timer(Duration(milliseconds: 500), () async {
|
||||||
if (_resizing) {
|
if (_resizing || !mounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_resizeTimer!.cancel();
|
_resizeTimer!.cancel();
|
||||||
_resizing = true;
|
_resizing = true;
|
||||||
var oldTexture = _texture;
|
var oldTexture = _texture;
|
||||||
_texture = null;
|
_texture = null;
|
||||||
setState(() {});
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var dpr = MediaQuery.of(context).devicePixelRatio;
|
var dpr = MediaQuery.of(context).devicePixelRatio;
|
||||||
|
|
||||||
_texture = await widget.plugin.resizeTexture(oldTexture!,
|
_texture = await ThermionFlutterPlugin.resizeTexture(oldTexture!,
|
||||||
(dpr * newSize.width).ceil(), (dpr * newSize.height).ceil(), 0, 0);
|
(dpr * newSize.width).ceil(), (dpr * newSize.height).ceil(), 0, 0);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
_resizing = false;
|
_resizing = false;
|
||||||
|
|||||||
@@ -2,4 +2,6 @@ library thermion_flutter;
|
|||||||
|
|
||||||
export 'thermion/thermion_flutter_plugin.dart';
|
export 'thermion/thermion_flutter_plugin.dart';
|
||||||
export 'thermion/widgets/thermion_widget.dart';
|
export 'thermion/widgets/thermion_widget.dart';
|
||||||
|
export 'thermion/widgets/camera/gestures/thermion_gesture_detector.dart';
|
||||||
|
|
||||||
export 'package:thermion_dart/thermion_dart.dart';
|
export 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
|||||||
@@ -871,7 +871,7 @@ void thermion_flutter_plugin_register_with_registrar(FlPluginRegistrar* registra
|
|||||||
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
|
||||||
g_autoptr(FlMethodChannel) channel =
|
g_autoptr(FlMethodChannel) channel =
|
||||||
fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
|
fl_method_channel_new(fl_plugin_registrar_get_messenger(registrar),
|
||||||
"app.polyvox.filament/event",
|
"dev.thermion.flutter/event",
|
||||||
FL_METHOD_CODEC(codec));
|
FL_METHOD_CODEC(codec));
|
||||||
fl_method_channel_set_method_call_handler(channel, method_call_cb,
|
fl_method_channel_set_method_call_handler(channel, method_call_cb,
|
||||||
g_object_ref(plugin),
|
g_object_ref(plugin),
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ public class SwiftThermionFlutterPlugin: NSObject, FlutterPlugin {
|
|||||||
var texture: ThermionFlutterTexture?
|
var texture: ThermionFlutterTexture?
|
||||||
|
|
||||||
var createdAt = Date()
|
var createdAt = Date()
|
||||||
|
|
||||||
|
var destroying = false
|
||||||
|
|
||||||
var resources:[UInt32:NSData] = [:]
|
var resources:[UInt32:NSData] = [:]
|
||||||
|
|
||||||
@@ -65,48 +67,59 @@ public class SwiftThermionFlutterPlugin: NSObject, FlutterPlugin {
|
|||||||
public static func register(with registrar: FlutterPluginRegistrar) {
|
public static func register(with registrar: FlutterPluginRegistrar) {
|
||||||
let _messenger = registrar.messenger;
|
let _messenger = registrar.messenger;
|
||||||
messenger = _messenger;
|
messenger = _messenger;
|
||||||
let channel = FlutterMethodChannel(name: "app.polyvox.filament/event", binaryMessenger: _messenger)
|
let channel = FlutterMethodChannel(name: "dev.thermion.flutter/event", binaryMessenger: _messenger)
|
||||||
let instance = SwiftThermionFlutterPlugin(textureRegistry: registrar.textures, registrar:registrar)
|
let instance = SwiftThermionFlutterPlugin(textureRegistry: registrar.textures, registrar:registrar)
|
||||||
registrar.addMethodCallDelegate(instance, channel: channel)
|
registrar.addMethodCallDelegate(instance, channel: channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var resourceLoaderWrapper:UnsafeMutablePointer<ResourceLoaderWrapper>? = nil
|
||||||
|
var renderCallbackHolder:[Any] = []
|
||||||
|
|
||||||
init(textureRegistry: FlutterTextureRegistry, registrar:FlutterPluginRegistrar) {
|
init(textureRegistry: FlutterTextureRegistry, registrar:FlutterPluginRegistrar) {
|
||||||
self.registry = textureRegistry;
|
self.registry = textureRegistry;
|
||||||
self.registrar = registrar
|
self.registrar = registrar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
|
||||||
let methodName = call.method;
|
let methodName = call.method;
|
||||||
switch methodName {
|
switch methodName {
|
||||||
case "getResourceLoaderWrapper":
|
case "getResourceLoaderWrapper":
|
||||||
var resourceLoaderWrapper = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque())
|
if(resourceLoaderWrapper == nil) {
|
||||||
result(unsafeBitCast(resourceLoaderWrapper, to:Int64.self))
|
resourceLoaderWrapper = make_resource_loader(loadResource, freeResource, Unmanaged.passUnretained(self).toOpaque())
|
||||||
|
}
|
||||||
|
result(Int64(Int(bitPattern: resourceLoaderWrapper!)))
|
||||||
case "getRenderCallback":
|
case "getRenderCallback":
|
||||||
let renderCallback = markTextureFrameAvailable
|
if(renderCallbackHolder.isEmpty) {
|
||||||
let resultArray:[Any] = [
|
renderCallbackHolder.append(unsafeBitCast(markTextureFrameAvailable, to:Int64.self))
|
||||||
unsafeBitCast(renderCallback, to:Int64.self), unsafeBitCast(Unmanaged.passUnretained(self), to:UInt64.self)]
|
renderCallbackHolder.append(unsafeBitCast(Unmanaged.passUnretained(self), to:UInt64.self))
|
||||||
result(resultArray)
|
}
|
||||||
|
result(renderCallbackHolder)
|
||||||
case "getDriverPlatform":
|
case "getDriverPlatform":
|
||||||
result(nil)
|
result(nil)
|
||||||
case "getSharedContext":
|
case "getSharedContext":
|
||||||
result(nil)
|
result(nil)
|
||||||
case "createTexture":
|
case "createTexture":
|
||||||
|
if(destroying) {
|
||||||
|
result(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
let args = call.arguments as! [Any]
|
let args = call.arguments as! [Any]
|
||||||
let width = args[0] as! Int64
|
let width = args[0] as! Int64
|
||||||
let height = args[1] as! Int64
|
let height = args[1] as! Int64
|
||||||
|
|
||||||
self.texture = ThermionFlutterTexture(registry: registry, width: width, height: height)
|
self.texture = ThermionFlutterTexture(registry: registry, width: width, height: height)
|
||||||
|
|
||||||
if(self.texture?.metalTextureAddress == -1) {
|
if(self.texture!.texture.metalTextureAddress == -1) {
|
||||||
result(nil)
|
result(nil)
|
||||||
} else {
|
} else {
|
||||||
result([self.texture!.flutterTextureId as Any, self.texture?.metalTextureAddress, nil])
|
result([self.texture!.flutterTextureId as Any, self.texture!.texture.metalTextureAddress, nil])
|
||||||
}
|
}
|
||||||
case "destroyTexture":
|
case "destroyTexture":
|
||||||
|
self.destroying = true
|
||||||
self.texture?.destroy()
|
self.texture?.destroy()
|
||||||
self.texture = nil
|
self.texture = nil
|
||||||
result(true)
|
result(true)
|
||||||
|
self.destroying = false
|
||||||
default:
|
default:
|
||||||
result(FlutterMethodNotImplemented)
|
result(FlutterMethodNotImplemented)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,18 +11,20 @@ import GLKit
|
|||||||
] as [CFString : Any] as CFDictionary
|
] as [CFString : Any] as CFDictionary
|
||||||
|
|
||||||
@objc public var cvMetalTextureCache:CVMetalTextureCache?
|
@objc public var cvMetalTextureCache:CVMetalTextureCache?
|
||||||
|
@objc public var metalDevice:MTLDevice?
|
||||||
|
|
||||||
@objc public var cvMetalTexture:CVMetalTexture?
|
@objc public var cvMetalTexture:CVMetalTexture?
|
||||||
@objc public var metalTexture:MTLTexture?
|
@objc public var metalTexture:MTLTexture?
|
||||||
@objc public var metalDevice:MTLDevice?
|
|
||||||
@objc public var metalTextureAddress:Int = -1
|
@objc public var metalTextureAddress:Int = -1
|
||||||
|
|
||||||
@objc override public init() {
|
@objc override public init() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public init(width:Int64, height:Int64) {
|
@objc public init(width:Int64, height:Int64) {
|
||||||
|
if(self.metalDevice == nil) {
|
||||||
self.metalDevice = MTLCreateSystemDefaultDevice()!
|
self.metalDevice = MTLCreateSystemDefaultDevice()!
|
||||||
|
}
|
||||||
|
|
||||||
// create pixel buffer
|
// create pixel buffer
|
||||||
if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height),
|
if(CVPixelBufferCreate(kCFAllocatorDefault, Int(width), Int(height),
|
||||||
@@ -31,37 +33,36 @@ import GLKit
|
|||||||
metalTextureAddress = -1;
|
metalTextureAddress = -1;
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if self.cvMetalTextureCache == nil {
|
||||||
var cvret = CVMetalTextureCacheCreate(
|
let cacheCreationResult = CVMetalTextureCacheCreate(
|
||||||
kCFAllocatorDefault,
|
kCFAllocatorDefault,
|
||||||
nil,
|
nil,
|
||||||
metalDevice!,
|
self.metalDevice!,
|
||||||
nil,
|
nil,
|
||||||
&cvMetalTextureCache);
|
&self.cvMetalTextureCache)
|
||||||
if(cvret != 0) {
|
if(cacheCreationResult != kCVReturnSuccess) {
|
||||||
print("Error creating Metal texture cache")
|
print("Error creating Metal texture cache")
|
||||||
metalTextureAddress = -1
|
metalTextureAddress = -1
|
||||||
return
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cvret = CVMetalTextureCacheCreateTextureFromImage(
|
let cvret = CVMetalTextureCacheCreateTextureFromImage(
|
||||||
kCFAllocatorDefault,
|
kCFAllocatorDefault,
|
||||||
cvMetalTextureCache!,
|
self.cvMetalTextureCache!,
|
||||||
pixelBuffer!, nil,
|
pixelBuffer!, nil,
|
||||||
MTLPixelFormat.bgra8Unorm,
|
MTLPixelFormat.bgra8Unorm,
|
||||||
Int(width), Int(height),
|
Int(width), Int(height),
|
||||||
0,
|
0,
|
||||||
&cvMetalTexture)
|
&cvMetalTexture)
|
||||||
if(cvret != 0) {
|
if(cvret != kCVReturnSuccess) {
|
||||||
print("Error creating texture from image")
|
print("Error creating texture from image")
|
||||||
metalTextureAddress = -1
|
metalTextureAddress = -1
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
metalTexture = CVMetalTextureGetTexture(cvMetalTexture!)
|
metalTexture = CVMetalTextureGetTexture(cvMetalTexture!)
|
||||||
let metalTexturePtr = Unmanaged.passUnretained(metalTexture!).toOpaque()
|
let metalTexturePtr = Unmanaged.passRetained(metalTexture!).toOpaque()
|
||||||
metalTextureAddress = Int(bitPattern:metalTexturePtr)
|
metalTextureAddress = Int(bitPattern:metalTexturePtr)
|
||||||
|
|
||||||
print("Created metal texture @ \(metalTextureAddress)")
|
|
||||||
|
|
||||||
// CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
// CVPixelBufferLockBaseAddress(pixelBuffer!, CVPixelBufferLockFlags(rawValue: 0))
|
||||||
// let bufferWidth = Int(CVPixelBufferGetWidth(pixelBuffer!))
|
// let bufferWidth = Int(CVPixelBufferGetWidth(pixelBuffer!))
|
||||||
// let bufferHeight = Int(CVPixelBufferGetHeight(pixelBuffer!))
|
// let bufferHeight = Int(CVPixelBufferGetHeight(pixelBuffer!))
|
||||||
@@ -95,7 +96,12 @@ import GLKit
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc public func destroyTexture() {
|
@objc public func destroyTexture() {
|
||||||
metalTexture = nil
|
CVMetalTextureCacheFlush(self.cvMetalTextureCache!, 0)
|
||||||
|
self.metalTexture = nil
|
||||||
|
self.cvMetalTexture = nil
|
||||||
|
self.pixelBuffer = nil
|
||||||
|
self.metalDevice = nil
|
||||||
|
self.cvMetalTextureCache = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,20 +2,24 @@ import Foundation
|
|||||||
import GLKit
|
import GLKit
|
||||||
import FlutterMacOS
|
import FlutterMacOS
|
||||||
|
|
||||||
public class ThermionFlutterTexture : ThermionDartTexture, FlutterTexture {
|
public class ThermionFlutterTexture : NSObject, FlutterTexture {
|
||||||
|
|
||||||
var flutterTextureId: Int64 = -1
|
var flutterTextureId: Int64 = -1
|
||||||
var registry: FlutterTextureRegistry
|
var registry: FlutterTextureRegistry
|
||||||
|
var texture: ThermionDartTexture
|
||||||
|
|
||||||
init(registry:FlutterTextureRegistry, width:Int64, height:Int64) {
|
init(registry:FlutterTextureRegistry, width:Int64, height:Int64) {
|
||||||
self.registry = registry
|
self.registry = registry
|
||||||
super.init(width:width, height:height)
|
self.texture = ThermionDartTexture(width:width, height: height)
|
||||||
|
super.init()
|
||||||
self.flutterTextureId = registry.register(self)
|
self.flutterTextureId = registry.register(self)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
|
public func copyPixelBuffer() -> Unmanaged<CVPixelBuffer>? {
|
||||||
return Unmanaged.passRetained(pixelBuffer!);
|
if(self.texture.pixelBuffer == nil) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return Unmanaged.passRetained(self.texture.pixelBuffer!);
|
||||||
}
|
}
|
||||||
|
|
||||||
public func onTextureUnregistered(_ texture:FlutterTexture) {
|
public func onTextureUnregistered(_ texture:FlutterTexture) {
|
||||||
@@ -24,7 +28,7 @@ public class ThermionFlutterTexture : ThermionDartTexture, FlutterTexture {
|
|||||||
|
|
||||||
public func destroy() {
|
public func destroy() {
|
||||||
self.registry.unregisterTexture(self.flutterTextureId)
|
self.registry.unregisterTexture(self.flutterTextureId)
|
||||||
self.destroyTexture()
|
self.texture.destroyTexture()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef RESOURCE_BUFFER_H
|
||||||
|
#define RESOURCE_BUFFER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// A ResourceBuffer is a unified interface for working with
|
||||||
|
// binary assets across various platforms.
|
||||||
|
// This is simply:
|
||||||
|
// 1) a pointer to some data
|
||||||
|
// 2) the length of the data
|
||||||
|
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
|
||||||
|
//
|
||||||
|
typedef struct ResourceBuffer
|
||||||
|
{
|
||||||
|
const void *const data;
|
||||||
|
const int32_t size;
|
||||||
|
const int32_t id;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
ResourceBuffer(void *const data, int32_t size, int32_t id) : data(data), size(size), id(id) {}
|
||||||
|
#endif
|
||||||
|
} ResourceBuffer;
|
||||||
|
|
||||||
|
typedef void (*LoadFilamentResourceIntoOutPointer)(const char *uri, ResourceBuffer *out);
|
||||||
|
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
|
||||||
|
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
|
||||||
|
typedef void (*FreeFilamentResource)(ResourceBuffer);
|
||||||
|
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
|
||||||
|
|
||||||
|
typedef struct ResourceLoaderWrapper
|
||||||
|
{
|
||||||
|
LoadFilamentResource loadResource;
|
||||||
|
FreeFilamentResource freeResource;
|
||||||
|
LoadFilamentResourceFromOwner loadFromOwner;
|
||||||
|
FreeFilamentResourceFromOwner freeFromOwner;
|
||||||
|
void *owner;
|
||||||
|
LoadFilamentResourceIntoOutPointer loadToOut;
|
||||||
|
} ResourceLoaderWrapper;
|
||||||
|
|
||||||
|
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
#ifndef RESOURCE_BUFFER_H
|
|
||||||
#define RESOURCE_BUFFER_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
//
|
|
||||||
// A ResourceBuffer is a unified interface for working with
|
|
||||||
// binary assets across various platforms.
|
|
||||||
// This is simply:
|
|
||||||
// 1) a pointer to some data
|
|
||||||
// 2) the length of the data
|
|
||||||
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
|
|
||||||
//
|
|
||||||
struct ResourceBuffer
|
|
||||||
{
|
|
||||||
const void *const data;
|
|
||||||
const int32_t size;
|
|
||||||
const int32_t id;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct ResourceBuffer ResourceBuffer;
|
|
||||||
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
|
|
||||||
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
|
|
||||||
typedef void (*FreeFilamentResource)(ResourceBuffer);
|
|
||||||
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
|
|
||||||
|
|
||||||
struct ResourceLoaderWrapper
|
|
||||||
{
|
|
||||||
LoadFilamentResource loadResource;
|
|
||||||
FreeFilamentResource freeResource;
|
|
||||||
LoadFilamentResourceFromOwner loadFromOwner;
|
|
||||||
FreeFilamentResourceFromOwner freeFromOwner;
|
|
||||||
void *owner;
|
|
||||||
};
|
|
||||||
typedef struct ResourceLoaderWrapper ResourceLoaderWrapper;
|
|
||||||
|
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
|
||||||
|
|
||||||
namespace thermion_filament {
|
|
||||||
|
|
||||||
struct ResourceLoaderWrapperImpl : public ResourceLoaderWrapper
|
|
||||||
{
|
|
||||||
|
|
||||||
ResourceLoaderWrapperImpl(LoadFilamentResource loader, FreeFilamentResource freeResource)
|
|
||||||
{
|
|
||||||
loadFromOwner = nullptr;
|
|
||||||
freeFromOwner = nullptr;
|
|
||||||
loadResource = loader;
|
|
||||||
freeResource = freeResource;
|
|
||||||
owner = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceLoaderWrapperImpl(LoadFilamentResourceFromOwner loader, FreeFilamentResourceFromOwner freeResource, void * owner)
|
|
||||||
{
|
|
||||||
loadResource = nullptr;
|
|
||||||
freeResource = nullptr;
|
|
||||||
loadFromOwner = loader;
|
|
||||||
freeFromOwner = freeResource;
|
|
||||||
owner = owner;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceBuffer load(const char *uri) const
|
|
||||||
{
|
|
||||||
if (loadFromOwner)
|
|
||||||
{
|
|
||||||
auto rb = loadFromOwner(uri, owner);
|
|
||||||
return rb;
|
|
||||||
}
|
|
||||||
auto rb = loadResource(uri);
|
|
||||||
return rb;
|
|
||||||
}
|
|
||||||
|
|
||||||
void free(ResourceBuffer rb) const
|
|
||||||
{
|
|
||||||
if (freeFromOwner)
|
|
||||||
{
|
|
||||||
freeFromOwner(rb, owner);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
freeResource(rb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -3,11 +3,14 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.h"
|
||||||
|
|
||||||
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
|
ResourceLoaderWrapper *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner)
|
||||||
{
|
{
|
||||||
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
|
ResourceLoaderWrapper *rlw = (ResourceLoaderWrapper *)malloc(sizeof(ResourceLoaderWrapper));
|
||||||
|
rlw->loadResource = NULL;
|
||||||
|
rlw->freeResource = NULL;
|
||||||
|
rlw->loadToOut = NULL;
|
||||||
rlw->loadFromOwner = loadFn;
|
rlw->loadFromOwner = loadFn;
|
||||||
rlw->freeFromOwner = freeFn;
|
rlw->freeFromOwner = freeFn;
|
||||||
rlw->owner = owner;
|
rlw->owner = owner;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ A new Flutter plugin project.
|
|||||||
s.license = { :file => '../LICENSE' }
|
s.license = { :file => '../LICENSE' }
|
||||||
s.author = { 'Your Company' => 'email@example.com' }
|
s.author = { 'Your Company' => 'email@example.com' }
|
||||||
s.source = { :path => '.' }
|
s.source = { :path => '.' }
|
||||||
s.source_files = 'Classes/*', 'include/ResourceBuffer.hpp','include/SwiftThermionFlutterPlugin-Bridging-Header.h'
|
s.source_files = 'Classes/*', 'include/ResourceBuffer.h','include/SwiftThermionFlutterPlugin-Bridging-Header.h'
|
||||||
s.public_header_files = 'include/SwiftThermionFlutterPlugin-Bridging-Header.h', 'include/ResourceBuffer.hpp'
|
s.public_header_files = 'include/SwiftThermionFlutterPlugin-Bridging-Header.h', 'include/ResourceBuffer.h'
|
||||||
s.dependency 'FlutterMacOS'
|
s.dependency 'FlutterMacOS'
|
||||||
|
|
||||||
s.platform = :osx, '13'
|
s.platform = :osx, '13'
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
name: thermion_flutter
|
name: thermion_flutter
|
||||||
description: Flutter plugin for 3D rendering with the Thermion toolkit.
|
description: Flutter plugin for 3D rendering with the Thermion toolkit.
|
||||||
version: 0.0.3
|
version: 0.1.1+7
|
||||||
homepage: https://docs.page/nmfisher/thermion
|
homepage: https://docs.page/nmfisher/thermion
|
||||||
repository: https://github.com/nmfisher/thermion
|
repository: https://github.com/nmfisher/thermion
|
||||||
|
|
||||||
@@ -17,10 +17,11 @@ dependencies:
|
|||||||
plugin_platform_interface: ^2.0.0
|
plugin_platform_interface: ^2.0.0
|
||||||
ffi: ^2.1.2
|
ffi: ^2.1.2
|
||||||
animation_tools_dart: ^0.0.4
|
animation_tools_dart: ^0.0.4
|
||||||
thermion_dart: ^0.0.4
|
thermion_dart: ^0.1.1+2
|
||||||
thermion_flutter_platform_interface: ^0.0.1
|
thermion_flutter_platform_interface: ^0.1.0+6
|
||||||
thermion_flutter_ffi: ^0.0.1
|
thermion_flutter_ffi: ^0.1.0+6
|
||||||
thermion_flutter_web: ^0.0.1
|
thermion_flutter_web: ^0.0.1+6
|
||||||
|
logging: ^1.2.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#pragma comment(lib, "dwmapi.lib")
|
#pragma comment(lib, "dwmapi.lib")
|
||||||
#pragma comment(lib, "comctl32.lib")
|
#pragma comment(lib, "comctl32.lib")
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
static constexpr auto kClassName = L"FLUTTER_FILAMENT_WINDOW";
|
static constexpr auto kClassName = L"FLUTTER_FILAMENT_WINDOW";
|
||||||
static constexpr auto kWindowName = L"thermion_flutter_window";
|
static constexpr auto kWindowName = L"thermion_flutter_window";
|
||||||
@@ -354,4 +354,4 @@ void BackingWindow::Resize(int width, int height, int left, int top) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HWND BackingWindow::GetHandle() { return _windowHandle; }
|
HWND BackingWindow::GetHandle() { return _windowHandle; }
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include <flutter/plugin_registrar_windows.h>
|
#include <flutter/plugin_registrar_windows.h>
|
||||||
#include <flutter/standard_method_codec.h>
|
#include <flutter/standard_method_codec.h>
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class BackingWindow {
|
class BackingWindow {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#pragma comment(lib, "dwmapi.lib")
|
#pragma comment(lib, "dwmapi.lib")
|
||||||
#pragma comment(lib, "comctl32.lib")
|
#pragma comment(lib, "comctl32.lib")
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
FlutterEGLContext::FlutterEGLContext(
|
FlutterEGLContext::FlutterEGLContext(
|
||||||
flutter::PluginRegistrarWindows* pluginRegistrar,
|
flutter::PluginRegistrarWindows* pluginRegistrar,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
#include "backend/platforms/PlatformEGL.h"
|
#include "backend/platforms/PlatformEGL.h"
|
||||||
#include "flutter_render_context.h"
|
#include "flutter_render_context.h"
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class FlutterEGLContext : public FlutterRenderContext {
|
class FlutterEGLContext : public FlutterRenderContext {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
static void logEglError(const char *name) noexcept {
|
static void logEglError(const char *name) noexcept {
|
||||||
const char *err;
|
const char *err;
|
||||||
@@ -240,4 +240,4 @@ FlutterAngleTexture::FlutterAngleTexture(
|
|||||||
result->Success(resultList);
|
result->Success(resultList);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
typedef uint32_t GLuint;
|
typedef uint32_t GLuint;
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class FlutterAngleTexture : public FlutterTextureBuffer {
|
class FlutterAngleTexture : public FlutterTextureBuffer {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "flutter_texture_buffer.h"
|
#include "flutter_texture_buffer.h"
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class FlutterRenderContext {
|
class FlutterRenderContext {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#include <flutter/texture_registrar.h>
|
#include <flutter/texture_registrar.h>
|
||||||
|
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class FlutterTextureBuffer {
|
class FlutterTextureBuffer {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#ifndef RESOURCE_BUFFER_H
|
||||||
|
#define RESOURCE_BUFFER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// A ResourceBuffer is a unified interface for working with
|
||||||
|
// binary assets across various platforms.
|
||||||
|
// This is simply:
|
||||||
|
// 1) a pointer to some data
|
||||||
|
// 2) the length of the data
|
||||||
|
// 3) an ID that can be passed back to the native platform to release the underlying asset when needed.
|
||||||
|
//
|
||||||
|
typedef struct ResourceBuffer
|
||||||
|
{
|
||||||
|
const void *const data;
|
||||||
|
const int32_t size;
|
||||||
|
const int32_t id;
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
ResourceBuffer(void *const data, int32_t size, int32_t id) : data(data), size(size), id(id) {}
|
||||||
|
#endif
|
||||||
|
} ResourceBuffer;
|
||||||
|
|
||||||
|
typedef void (*LoadFilamentResourceIntoOutPointer)(const char *uri, ResourceBuffer *out);
|
||||||
|
typedef ResourceBuffer (*LoadFilamentResource)(const char *uri);
|
||||||
|
typedef ResourceBuffer (*LoadFilamentResourceFromOwner)(const char *const, void *const owner);
|
||||||
|
typedef void (*FreeFilamentResource)(ResourceBuffer);
|
||||||
|
typedef void (*FreeFilamentResourceFromOwner)(ResourceBuffer, void *const owner);
|
||||||
|
|
||||||
|
typedef struct ResourceLoaderWrapper
|
||||||
|
{
|
||||||
|
LoadFilamentResource loadResource;
|
||||||
|
FreeFilamentResource freeResource;
|
||||||
|
LoadFilamentResourceFromOwner loadFromOwner;
|
||||||
|
FreeFilamentResourceFromOwner freeFromOwner;
|
||||||
|
void *owner;
|
||||||
|
LoadFilamentResourceIntoOutPointer loadToOut;
|
||||||
|
} ResourceLoaderWrapper;
|
||||||
|
|
||||||
|
void *make_resource_loader(LoadFilamentResourceFromOwner loadFn, FreeFilamentResourceFromOwner freeFn, void *const owner);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
void _release_callback(void *releaseContext) {
|
void _release_callback(void *releaseContext) {
|
||||||
// ((OpenGLTextureBuffer*)releaseContext)->unlock();
|
// ((OpenGLTextureBuffer*)releaseContext)->unlock();
|
||||||
@@ -141,4 +141,4 @@ OpenGLTextureBuffer::~OpenGLTextureBuffer() {
|
|||||||
wglMakeCurrent(NULL, NULL);
|
wglMakeCurrent(NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
typedef uint32_t GLuint;
|
typedef uint32_t GLuint;
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class OpenGLTextureBuffer : public FlutterTextureBuffer {
|
class OpenGLTextureBuffer : public FlutterTextureBuffer {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
#include "thermion_flutter_plugin.h"
|
#include "thermion_flutter_plugin.h"
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
namespace test {
|
namespace test {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -40,4 +40,4 @@ TEST(ThermionFlutterPlugin, GetPlatformVersion) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace test
|
} // namespace test
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
#include "wgl_context.h"
|
#include "wgl_context.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ void ThermionFlutterPlugin::RegisterWithRegistrar(
|
|||||||
flutter::PluginRegistrarWindows *registrar) {
|
flutter::PluginRegistrarWindows *registrar) {
|
||||||
auto channel =
|
auto channel =
|
||||||
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
|
||||||
registrar->messenger(), "app.polyvox.filament/event",
|
registrar->messenger(), "dev.thermion.flutter/event",
|
||||||
&flutter::StandardMethodCodec::GetInstance());
|
&flutter::StandardMethodCodec::GetInstance());
|
||||||
|
|
||||||
auto plugin = std::make_unique<ThermionFlutterPlugin>(
|
auto plugin = std::make_unique<ThermionFlutterPlugin>(
|
||||||
@@ -61,7 +61,6 @@ ThermionFlutterPlugin::ThermionFlutterPlugin(
|
|||||||
|
|
||||||
// attach the method call handler for incoming messages
|
// attach the method call handler for incoming messages
|
||||||
_channel->SetMethodCallHandler([=](const auto &call, auto result) {
|
_channel->SetMethodCallHandler([=](const auto &call, auto result) {
|
||||||
std::cout << call.method_name() << std::endl;
|
|
||||||
this->HandleMethodCall(call, std::move(result));
|
this->HandleMethodCall(call, std::move(result));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -275,4 +274,4 @@ void ThermionFlutterPlugin::HandleMethodCall(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
#include "GL/GL.h"
|
#include "GL/GL.h"
|
||||||
#include "GL/GLu.h"
|
#include "GL/GLu.h"
|
||||||
|
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.h"
|
||||||
|
|
||||||
#if USE_ANGLE
|
#if USE_ANGLE
|
||||||
#include "egl_context.h"
|
#include "egl_context.h"
|
||||||
@@ -22,7 +22,7 @@
|
|||||||
#include "wgl_context.h"
|
#include "wgl_context.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class ThermionFlutterPlugin : public flutter::Plugin {
|
class ThermionFlutterPlugin : public flutter::Plugin {
|
||||||
public:
|
public:
|
||||||
@@ -66,6 +66,6 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
|
|
||||||
#endif // FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
#endif // FLUTTER_PLUGIN_FLUTTER_FILAMENT_PLUGIN_H_
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "flutter_texture_buffer.h"
|
#include "flutter_texture_buffer.h"
|
||||||
|
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
|
WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
|
||||||
flutter::TextureRegistrar *textureRegistrar)
|
flutter::TextureRegistrar *textureRegistrar)
|
||||||
@@ -143,4 +143,4 @@ void WGLContext::CreateRenderingSurface(
|
|||||||
|
|
||||||
void *WGLContext::GetSharedContext() { return (void *)_context; }
|
void *WGLContext::GetSharedContext() { return (void *)_context; }
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_flutter
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#if WGL_USE_BACKING_WINDOW
|
#if WGL_USE_BACKING_WINDOW
|
||||||
#include "backing_window.h"
|
#include "backing_window.h"
|
||||||
#endif
|
#endif
|
||||||
namespace thermion_filament {
|
namespace thermion_flutter {
|
||||||
|
|
||||||
class WGLContext : public FlutterRenderContext {
|
class WGLContext : public FlutterRenderContext {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,2 +1,30 @@
|
|||||||
|
## 0.1.0+6
|
||||||
|
|
||||||
|
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
|
||||||
|
|
||||||
|
## 0.1.0-dev.0+6
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.0+5
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.0+4
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.0+3
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
|
## 0.1.0+2
|
||||||
|
|
||||||
|
- **REFACTOR**: rearrange some stubs/imports for easier web WASM deployment.
|
||||||
|
|
||||||
|
## 0.1.0+1
|
||||||
|
|
||||||
|
- Update a dependency to the latest release.
|
||||||
|
|
||||||
## 0.0.1
|
## 0.0.1
|
||||||
* First release of Dart-only package
|
* First release of Dart-only package
|
||||||
|
|||||||
@@ -2,25 +2,29 @@ import 'dart:async';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'package:thermion_dart/thermion_dart.dart';
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/thermion_viewer_ffi.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
|
||||||
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
/// A subclass of [ThermionViewerFFI] that uses Flutter platform channels
|
/// An implementation of [ThermionFlutterPlatform] that uses a Flutter platform
|
||||||
/// to create rendering contexts, callbacks and surfaces (either backing texture(s).
|
/// channel to create a rendering context, resource loaders, and
|
||||||
|
/// render target(s).
|
||||||
///
|
///
|
||||||
class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
||||||
final _channel = const MethodChannel("app.polyvox.filament/event");
|
final _channel = const MethodChannel("dev.thermion.flutter/event");
|
||||||
|
|
||||||
late final ThermionViewerFFI viewer;
|
ThermionViewerFFI? _viewer;
|
||||||
|
|
||||||
|
ThermionFlutterFFI._() {}
|
||||||
|
|
||||||
static void registerWith() {
|
static void registerWith() {
|
||||||
ThermionFlutterPlatform.instance = ThermionFlutterFFI();
|
ThermionFlutterPlatform.instance = ThermionFlutterFFI._();
|
||||||
}
|
}
|
||||||
|
|
||||||
final _textures = <ThermionFlutterTexture>{};
|
final _textures = <ThermionFlutterTexture>{};
|
||||||
|
|
||||||
Future initialize({String? uberArchivePath}) async {
|
Future<ThermionViewer> createViewer({String? uberArchivePath}) async {
|
||||||
var resourceLoader = Pointer<Void>.fromAddress(
|
var resourceLoader = Pointer<Void>.fromAddress(
|
||||||
await _channel.invokeMethod("getResourceLoaderWrapper"));
|
await _channel.invokeMethod("getResourceLoaderWrapper"));
|
||||||
|
|
||||||
@@ -46,22 +50,24 @@ class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
|||||||
? nullptr
|
? nullptr
|
||||||
: Pointer<Void>.fromAddress(sharedContext);
|
: Pointer<Void>.fromAddress(sharedContext);
|
||||||
|
|
||||||
viewer = ThermionViewerFFI(
|
_viewer = ThermionViewerFFI(
|
||||||
resourceLoader: resourceLoader,
|
resourceLoader: resourceLoader,
|
||||||
renderCallback: renderCallback,
|
renderCallback: renderCallback,
|
||||||
renderCallbackOwner: renderCallbackOwner,
|
renderCallbackOwner: renderCallbackOwner,
|
||||||
driver: driverPtr,
|
driver: driverPtr,
|
||||||
sharedContext: sharedContextPtr,
|
sharedContext: sharedContextPtr,
|
||||||
uberArchivePath: uberArchivePath);
|
uberArchivePath: uberArchivePath);
|
||||||
await viewer.initialized;
|
await _viewer!.initialized;
|
||||||
|
return _viewer!;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _creatingTexture = false;
|
bool _creatingTexture = false;
|
||||||
|
bool _destroyingTexture = false;
|
||||||
|
|
||||||
Future _waitForTextureCreationToComplete() async {
|
Future _waitForTextureCreationToComplete() async {
|
||||||
var iter = 0;
|
var iter = 0;
|
||||||
|
|
||||||
while (_creatingTexture) {
|
while (_creatingTexture || _destroyingTexture) {
|
||||||
await Future.delayed(Duration(milliseconds: 50));
|
await Future.delayed(Duration(milliseconds: 50));
|
||||||
iter++;
|
iter++;
|
||||||
if (iter > 10) {
|
if (iter > 10) {
|
||||||
@@ -104,10 +110,15 @@ class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
|||||||
|
|
||||||
if (_textures.length > 1) {
|
if (_textures.length > 1) {
|
||||||
throw Exception("Multiple textures not yet supported");
|
throw Exception("Multiple textures not yet supported");
|
||||||
} else if (_textures.length == 1 &&
|
} else if (_textures.length == 1) {
|
||||||
_textures.first.height == height &&
|
if (_textures.first.height == height && _textures.first.width == width) {
|
||||||
_textures.first.width == width) {
|
return _textures.first;
|
||||||
return _textures.first;
|
} else {
|
||||||
|
await _viewer!.setRendering(false);
|
||||||
|
await _viewer!.destroySwapChain();
|
||||||
|
await destroyTexture(_textures.first);
|
||||||
|
_textures.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_creatingTexture = true;
|
_creatingTexture = true;
|
||||||
@@ -125,39 +136,44 @@ class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
|||||||
print(
|
print(
|
||||||
"Created texture with flutter texture id ${flutterTextureId}, hardwareTextureId $hardwareTextureId and surfaceAddress $surfaceAddress");
|
"Created texture with flutter texture id ${flutterTextureId}, hardwareTextureId $hardwareTextureId and surfaceAddress $surfaceAddress");
|
||||||
|
|
||||||
viewer.viewportDimensions = (width.toDouble(), height.toDouble());
|
_viewer?.viewportDimensions = (width.toDouble(), height.toDouble());
|
||||||
|
|
||||||
final texture = ThermionFlutterTexture(
|
final texture = ThermionFlutterTexture(
|
||||||
flutterTextureId, hardwareTextureId, width, height, surfaceAddress);
|
flutterTextureId, hardwareTextureId, width, height, surfaceAddress);
|
||||||
|
|
||||||
await viewer.createSwapChain(width.toDouble(), height.toDouble(),
|
await _viewer?.createSwapChain(width.toDouble(), height.toDouble(),
|
||||||
surface: texture.surfaceAddress == null
|
surface: texture.surfaceAddress == null
|
||||||
? nullptr
|
? nullptr
|
||||||
: Pointer<Void>.fromAddress(texture.surfaceAddress!));
|
: Pointer<Void>.fromAddress(texture.surfaceAddress!));
|
||||||
|
|
||||||
if (texture.hardwareTextureId != null) {
|
if (texture.hardwareTextureId != null) {
|
||||||
print("Creating render target");
|
|
||||||
// ignore: unused_local_variable
|
// ignore: unused_local_variable
|
||||||
var renderTarget = await viewer.createRenderTarget(
|
var renderTarget = await _viewer?.createRenderTarget(
|
||||||
width.toDouble(), height.toDouble(), texture.hardwareTextureId!);
|
width.toDouble(), height.toDouble(), texture.hardwareTextureId!);
|
||||||
}
|
}
|
||||||
|
|
||||||
await viewer.updateViewportAndCameraProjection(
|
await _viewer?.updateViewportAndCameraProjection(
|
||||||
width.toDouble(), height.toDouble());
|
width.toDouble(), height.toDouble());
|
||||||
viewer.render();
|
_viewer?.render();
|
||||||
_creatingTexture = false;
|
_creatingTexture = false;
|
||||||
|
|
||||||
_textures.add(texture);
|
_textures.add(texture);
|
||||||
|
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// Called by [ThermionWidget] to destroy a texture. Don't call this yourself.
|
/// Destroy a texture and clean up the texture cache (if applicable).
|
||||||
///
|
///
|
||||||
Future destroyTexture(ThermionFlutterTexture texture) async {
|
Future destroyTexture(ThermionFlutterTexture texture) async {
|
||||||
await _channel.invokeMethod("destroyTexture", texture.flutterTextureId);
|
if (_creatingTexture || _destroyingTexture) {
|
||||||
|
throw Exception(
|
||||||
|
"Cannot destroy texture while concurrent call to createTexture/destroyTexture has not completed");
|
||||||
|
}
|
||||||
|
_destroyingTexture = true;
|
||||||
_textures.remove(texture);
|
_textures.remove(texture);
|
||||||
|
await _channel.invokeMethod("destroyTexture", texture.flutterTextureId);
|
||||||
|
_destroyingTexture = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool _resizing = false;
|
bool _resizing = false;
|
||||||
@@ -172,14 +188,14 @@ class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
|||||||
throw Exception("Resize underway");
|
throw Exception("Resize underway");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((width - viewer.viewportDimensions.$1).abs() < 0.001 ||
|
if ((width - _viewer!.viewportDimensions.$1).abs() < 0.001 ||
|
||||||
(height - viewer.viewportDimensions.$2).abs() < 0.001) {
|
(height - _viewer!.viewportDimensions.$2).abs() < 0.001) {
|
||||||
return texture;
|
return texture;
|
||||||
}
|
}
|
||||||
_resizing = true;
|
_resizing = true;
|
||||||
bool wasRendering = viewer.rendering;
|
bool wasRendering = _viewer!.rendering;
|
||||||
await viewer.setRendering(false);
|
await _viewer!.setRendering(false);
|
||||||
await viewer.destroySwapChain();
|
await _viewer!.destroySwapChain();
|
||||||
await destroyTexture(texture);
|
await destroyTexture(texture);
|
||||||
|
|
||||||
var result = await _channel
|
var result = await _channel
|
||||||
@@ -188,34 +204,29 @@ class ThermionFlutterFFI extends ThermionFlutterPlatform {
|
|||||||
if (result == null || result[0] == -1) {
|
if (result == null || result[0] == -1) {
|
||||||
throw Exception("Failed to create texture");
|
throw Exception("Failed to create texture");
|
||||||
}
|
}
|
||||||
viewer.viewportDimensions = (width.toDouble(), height.toDouble());
|
_viewer!.viewportDimensions = (width.toDouble(), height.toDouble());
|
||||||
var newTexture =
|
var newTexture =
|
||||||
ThermionFlutterTexture(result[0], result[1], width, height, result[2]);
|
ThermionFlutterTexture(result[0], result[1], width, height, result[2]);
|
||||||
|
|
||||||
await viewer.createSwapChain(width.toDouble(), height.toDouble(),
|
await _viewer!.createSwapChain(width.toDouble(), height.toDouble(),
|
||||||
surface: newTexture.surfaceAddress == null
|
surface: newTexture.surfaceAddress == null
|
||||||
? nullptr
|
? nullptr
|
||||||
: Pointer<Void>.fromAddress(newTexture.surfaceAddress!));
|
: Pointer<Void>.fromAddress(newTexture.surfaceAddress!));
|
||||||
|
|
||||||
if (newTexture.hardwareTextureId != null) {
|
if (newTexture.hardwareTextureId != null) {
|
||||||
// ignore: unused_local_variable
|
// ignore: unused_local_variable
|
||||||
var renderTarget = await viewer.createRenderTarget(
|
var renderTarget = await _viewer!.createRenderTarget(
|
||||||
width.toDouble(), height.toDouble(), newTexture.hardwareTextureId!);
|
width.toDouble(), height.toDouble(), newTexture.hardwareTextureId!);
|
||||||
}
|
}
|
||||||
await viewer.updateViewportAndCameraProjection(
|
await _viewer!
|
||||||
width.toDouble(), height.toDouble());
|
.updateViewportAndCameraProjection(width.toDouble(), height.toDouble());
|
||||||
|
|
||||||
viewer.viewportDimensions = (width.toDouble(), height.toDouble());
|
_viewer!.viewportDimensions = (width.toDouble(), height.toDouble());
|
||||||
if (wasRendering) {
|
if (wasRendering) {
|
||||||
await viewer.setRendering(true);
|
await _viewer!.setRendering(true);
|
||||||
}
|
}
|
||||||
_textures.add(newTexture);
|
_textures.add(newTexture);
|
||||||
_resizing = false;
|
_resizing = false;
|
||||||
return newTexture;
|
return newTexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
// TODO: implement dispose
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
name: thermion_flutter_ffi
|
name: thermion_flutter_ffi
|
||||||
description: An FFI interface for the thermion_flutter plugin (all platforms except web).
|
description: An FFI interface for the thermion_flutter plugin (all platforms except web).
|
||||||
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
|
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
|
||||||
version: 0.0.1
|
version: 0.1.0+6
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.0 <4.0.0"
|
sdk: ">=3.3.0 <4.0.0"
|
||||||
@@ -22,8 +22,8 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
plugin_platform_interface: ^2.1.0
|
plugin_platform_interface: ^2.1.0
|
||||||
thermion_flutter_platform_interface: ^0.0.1-pre
|
thermion_flutter_platform_interface: ^0.1.0+6
|
||||||
thermion_dart: ^0.0.1-pre2
|
thermion_dart: ^0.1.1+2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user