Compare commits
251 Commits
thermion_d
...
thermion_f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
951064e657 | ||
|
|
68ebf945a5 | ||
|
|
153817e859 | ||
|
|
ba0bc54fa7 | ||
|
|
9b99975017 | ||
|
|
e6a6862ba4 | ||
|
|
b7d3e9191a | ||
|
|
b461b2c5db | ||
|
|
8f7f48bcaa | ||
|
|
7dc8e394f7 | ||
|
|
f5c8faa5c3 | ||
|
|
c84b4010d1 | ||
|
|
b720c1294f | ||
|
|
d442ab5ce6 | ||
|
|
61fdf300f4 | ||
|
|
4dabca9160 | ||
|
|
85d6946645 | ||
|
|
4b1d8ce729 | ||
|
|
c52b0084ce | ||
|
|
8db725d8bd | ||
|
|
c67d1cbbc4 | ||
|
|
3ea4062e33 | ||
|
|
65e99b9212 | ||
|
|
e83193ba0d | ||
|
|
835338ef63 | ||
|
|
57872d2e40 | ||
|
|
b5a7996769 | ||
|
|
ddbb4ec5c6 | ||
|
|
7cb3080596 | ||
|
|
f6c91294aa | ||
|
|
412d333525 | ||
|
|
378dede02d | ||
|
|
0e3db2635f | ||
|
|
77147cbafd | ||
|
|
43e5fd7766 | ||
|
|
fc3ca3d6b3 | ||
|
|
51f52bb71b | ||
|
|
033c3f632d | ||
|
|
6d862ef36a | ||
|
|
f816274fb9 | ||
|
|
0816286696 | ||
|
|
b421df5e2f | ||
|
|
f6a136643d | ||
|
|
b5e278183a | ||
|
|
8e85042e37 | ||
|
|
f943756624 | ||
|
|
92814aed56 | ||
|
|
e8a1b976e1 | ||
|
|
ef48dbce30 | ||
|
|
196cc6b980 | ||
|
|
1788c74d4c | ||
|
|
74e808d1dc | ||
|
|
72dacc5b21 | ||
|
|
ebdaf65b89 | ||
|
|
fa43149c98 | ||
|
|
e8ae7193ee | ||
|
|
aa21c0fb76 | ||
|
|
10826466a4 | ||
|
|
3b2d7d8c47 | ||
|
|
212443cb8e | ||
|
|
523141d54b | ||
|
|
d8a0859f16 | ||
|
|
c70cc9abb5 | ||
|
|
66b626e605 | ||
|
|
4b28119318 | ||
|
|
666506aed0 | ||
|
|
a55f63a428 | ||
|
|
fb441e151c | ||
|
|
82d85386c0 | ||
|
|
242b2f6faa | ||
|
|
31d31dd583 | ||
|
|
f6077012b1 | ||
|
|
18bb45dcd8 | ||
|
|
10b919e4f4 | ||
|
|
98cedf821c | ||
|
|
729f72e768 | ||
|
|
d01861e949 | ||
|
|
adec48f253 | ||
|
|
27a8ce18d5 | ||
|
|
4b740a9f5a | ||
|
|
0b34b4546e | ||
|
|
c17919cd97 | ||
|
|
462f1f02bf | ||
|
|
ddc433a126 | ||
|
|
ab649e860d | ||
|
|
676ddc3773 | ||
|
|
7d2cf3f91b | ||
|
|
492d41d756 | ||
|
|
191c2fd709 | ||
|
|
027fc9ae04 | ||
|
|
b73d0e1e96 | ||
|
|
315f2b63b9 | ||
|
|
ad205679cb | ||
|
|
6ef8d19e94 | ||
|
|
6b0f25ca59 | ||
|
|
820d341f67 | ||
|
|
70f904d54c | ||
|
|
aee607908d | ||
|
|
c99c57e24d | ||
|
|
00d75be479 | ||
|
|
3a9bd31919 | ||
|
|
51be1bce39 | ||
|
|
822b8e14c1 | ||
|
|
2ab30a7933 | ||
|
|
1be8a5e862 | ||
|
|
98d61fa1b3 | ||
|
|
5b3d16a316 | ||
|
|
b6863828b4 | ||
|
|
98fefd0e52 | ||
|
|
d476d78e2b | ||
|
|
98113fb79f | ||
|
|
90827ff012 | ||
|
|
44078ba2e0 | ||
|
|
866219ee2e | ||
|
|
d785bd6b7e | ||
|
|
3e4e6653a8 | ||
|
|
8d250e2664 | ||
|
|
d455cea29e | ||
|
|
374e8eb910 | ||
|
|
833fc74b4c | ||
|
|
62417bfebd | ||
|
|
abc9ecbeee | ||
|
|
a1f71ab459 | ||
|
|
d123929fb4 | ||
|
|
141827c59c | ||
|
|
9fbcc9edaf | ||
|
|
83d9c5be30 | ||
|
|
6aadbbc3d0 | ||
|
|
d5bc865cf4 | ||
|
|
d766733489 | ||
|
|
f51c640d17 | ||
|
|
66f10b598a | ||
|
|
59957650aa | ||
|
|
d43fbd8964 | ||
|
|
f5de4349bf | ||
|
|
f67e1a021d | ||
|
|
33f2c5fbf7 | ||
|
|
6a7bde930d | ||
|
|
b827a2142b | ||
|
|
8bd2416bad | ||
|
|
3684eb248c | ||
|
|
9077632d1b | ||
|
|
d40261ae29 | ||
|
|
77dbb574c7 | ||
|
|
89a660144e | ||
|
|
7554af5d41 | ||
|
|
4b742fea2d | ||
|
|
a6c6cff8b6 | ||
|
|
5813753ef9 | ||
|
|
cf0dad2631 | ||
|
|
cfddb99a8b | ||
|
|
845d5bf223 | ||
|
|
dbbd972909 | ||
|
|
aba3ba24af | ||
|
|
81c27dde9f | ||
|
|
476b552fd0 | ||
|
|
5c4d5d4b9d | ||
|
|
ae5ef2c286 | ||
|
|
b0f3c8a087 | ||
|
|
43fc7ffc65 | ||
|
|
ee24fca20e | ||
|
|
a00fdbe042 | ||
|
|
c2eb28a8f5 | ||
|
|
4c6c20f3de | ||
|
|
b2ae8135c6 | ||
|
|
aecde97200 | ||
|
|
331caccc22 | ||
|
|
63e2b74bb1 | ||
|
|
433f03161c | ||
|
|
6ec84b6249 | ||
|
|
29b6a48816 | ||
|
|
00755fd417 | ||
|
|
9c5156e41a | ||
|
|
226c45ee2e | ||
|
|
e04390b2fe | ||
|
|
9a87eb4d9b | ||
|
|
2284d9d081 | ||
|
|
cf61369a8d | ||
|
|
4e14bd2396 | ||
|
|
0798d5c071 | ||
|
|
80d5b1d23f | ||
|
|
0bd87288d1 | ||
|
|
51e06c2eb9 | ||
|
|
b29663923d | ||
|
|
f57a323cda | ||
|
|
03ffe85113 | ||
|
|
4edc8aa85b | ||
|
|
04ecb4d56f | ||
|
|
0ac0a92024 | ||
|
|
ae1e14ddb7 | ||
|
|
aa246ab63a | ||
|
|
d4350d7d99 | ||
|
|
f07fe6084a | ||
|
|
4e29055a20 | ||
|
|
6d0c06a853 | ||
|
|
abe6e1fcb8 | ||
|
|
683105c4f7 | ||
|
|
6f2331582c | ||
|
|
f0f97e310c | ||
|
|
2331f2c31a | ||
|
|
704b7f6734 | ||
|
|
7ac7ae43ab | ||
|
|
d52b23d6b5 | ||
|
|
8b17916cd9 | ||
|
|
4a0f4e3ac8 | ||
|
|
85116f43a2 | ||
|
|
3ecb8920ea | ||
|
|
8923d97129 | ||
|
|
375e1cc887 | ||
|
|
78dcbc8bb9 | ||
|
|
a3f7b98bf7 | ||
|
|
12b61e8767 | ||
|
|
0e3b014c2c | ||
|
|
10db8c39f3 | ||
|
|
371bcb3706 | ||
|
|
714c575409 | ||
|
|
c0941e3b7f | ||
|
|
026acb7467 | ||
|
|
3c05cc6a43 | ||
|
|
f1a2926bdf | ||
|
|
88e8a138ac | ||
|
|
53d0301828 | ||
|
|
b10fec1963 | ||
|
|
08e1eb7778 | ||
|
|
d6713c090c | ||
|
|
497ecbf881 | ||
|
|
6f7d03737e | ||
|
|
ad60c6bbe1 | ||
|
|
92fdda722b | ||
|
|
3cc876f972 | ||
|
|
7d1e706045 | ||
|
|
11756fcedd | ||
|
|
2e1f2cd56d | ||
|
|
c08611b2c3 | ||
|
|
f87f89427d | ||
|
|
c3319ebbf3 | ||
|
|
f7b765c5d0 | ||
|
|
9512b74008 | ||
|
|
5a3517f953 | ||
|
|
731c4981c9 | ||
|
|
8f20a8a859 | ||
|
|
7693a0fe14 | ||
|
|
98c3676fdf | ||
|
|
d7664a9746 | ||
|
|
d868fd6970 | ||
|
|
300396b97e | ||
|
|
1d8faa70a1 | ||
|
|
1051b1bb0e | ||
|
|
c367824041 | ||
|
|
81cedf0d43 | ||
|
|
16c6203b97 |
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -153,10 +153,7 @@ thermion_dart/native/lib/ios/libibl-lite.a filter=lfs diff=lfs merge=lfs -text
|
|||||||
thermion_dart/native/lib/ios/libimageio.a filter=lfs diff=lfs merge=lfs -text
|
thermion_dart/native/lib/ios/libimageio.a filter=lfs diff=lfs merge=lfs -text
|
||||||
materials/Makefile filter=lfs diff=lfs merge=lfs -text
|
materials/Makefile filter=lfs diff=lfs merge=lfs -text
|
||||||
materials/gizmo.filamat filter=lfs diff=lfs merge=lfs -text
|
materials/gizmo.filamat filter=lfs diff=lfs merge=lfs -text
|
||||||
materials/gizmo.mat filter=lfs diff=lfs merge=lfs -text
|
|
||||||
materials/image.filamat filter=lfs diff=lfs merge=lfs -text
|
materials/image.filamat filter=lfs diff=lfs merge=lfs -text
|
||||||
materials/image.mat filter=lfs diff=lfs merge=lfs -text
|
|
||||||
materials/unlit_fade.mat filter=lfs diff=lfs merge=lfs -text
|
|
||||||
materials/unlit_opaque.mat filter=lfs diff=lfs merge=lfs -text
|
materials/unlit_opaque.mat filter=lfs diff=lfs merge=lfs -text
|
||||||
thermion_dart/native/lib/android/arm64-v8a/libktxreader.a filter=lfs diff=lfs merge=lfs -text
|
thermion_dart/native/lib/android/arm64-v8a/libktxreader.a filter=lfs diff=lfs merge=lfs -text
|
||||||
thermion_dart/native/lib/android/armeabi-v7a/libcamutils.a filter=lfs diff=lfs merge=lfs -text
|
thermion_dart/native/lib/android/armeabi-v7a/libcamutils.a filter=lfs diff=lfs merge=lfs -text
|
||||||
|
|||||||
150
CHANGELOG.md
150
CHANGELOG.md
@@ -3,6 +3,156 @@
|
|||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||||
|
|
||||||
|
## 2024-09-25
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- [`thermion_flutter` - `v0.2.0-dev.3.0`](#thermion_flutter---v020-dev30)
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- There are no other changes in this release.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.2.0-dev.3.0`
|
||||||
|
|
||||||
|
- **BREAKING** **FIX**: remove EntityControllerMouseWidget (replace with GestureHandler).
|
||||||
|
- **BREAKING** **CHORE**: (flutter) cleanup for pub.dev publishing.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-09-25
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- [`thermion_flutter` - `v0.2.0-dev.2.0`](#thermion_flutter---v020-dev20)
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- There are no other changes in this release.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.2.0-dev.2.0`
|
||||||
|
|
||||||
|
- **BREAKING** **CHORE**: remove EntityListWidget - will replace with new Scene.
|
||||||
|
|
||||||
|
|
||||||
|
## 2024-09-25
|
||||||
|
|
||||||
|
### Changes
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Packages with breaking changes:
|
||||||
|
|
||||||
|
- [`thermion_dart` - `v0.2.0-dev.1.0`](#thermion_dart---v020-dev10)
|
||||||
|
- [`thermion_flutter` - `v0.2.0-dev.1.0`](#thermion_flutter---v020-dev10)
|
||||||
|
- [`thermion_flutter_ffi` - `v0.2.0-dev.1.0`](#thermion_flutter_ffi---v020-dev10)
|
||||||
|
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.1.0`](#thermion_flutter_platform_interface---v020-dev10)
|
||||||
|
- [`thermion_flutter_web` - `v0.1.0-dev.1.0`](#thermion_flutter_web---v010-dev10)
|
||||||
|
|
||||||
|
Packages with other changes:
|
||||||
|
|
||||||
|
- There are no other changes in this release.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `thermion_dart` - `v0.2.0-dev.1.0`
|
||||||
|
|
||||||
|
- **REFACTOR**: native types.
|
||||||
|
- **REFACTOR**: native types.
|
||||||
|
- **REFACTOR**: move native types to own header, add methods for create/destroy material instance, add priority/layer to load_glb_from_buffer.
|
||||||
|
- **REFACTOR**: Dart types.
|
||||||
|
- **FIX**: (web) add emscripten guards for flushAndWait call when swapchain destroyed.
|
||||||
|
- **FIX**: ignore pick results directly on axis.
|
||||||
|
- **FIX**: properly destroy entities/material/etc in Gizmo on destruction, remove custom scene creation logic.
|
||||||
|
- **FIX**: add check for nan NDC coordinates for viewport translation.
|
||||||
|
- **FIX**: (wasm) use correct coords for pick, free memory correctly, keep pixelratio copy.
|
||||||
|
- **FIX**: add more nan checks for gizmo manipulation.
|
||||||
|
- **FIX**: emscripten export visibility for add_light.
|
||||||
|
- **FIX**: add Fence to capture() and set stencil buffer by default.
|
||||||
|
- **FEAT**: add removeStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionViewer.
|
||||||
|
- **FEAT**: add removeStencilHighlight, accept color param for setStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionDartApi.
|
||||||
|
- **FEAT**: add flag for keepData for gltf instancing, add highlightScene, add stencilHighlight method.
|
||||||
|
- **FEAT**: grid uses own material.
|
||||||
|
- **FEAT**: parent the cloned entity instance when setting stencil highlight.
|
||||||
|
- **FEAT**: add grid material.
|
||||||
|
- **FEAT**: expose setLightDirection and setLightPosition.
|
||||||
|
- **FEAT**: move HighlightOverlay to nested class, move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector.
|
||||||
|
- **FEAT**: move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector and removeStencilHighlight.
|
||||||
|
- **FEAT**: add setGizmoVisibility/pickGizmo methods to ThermionViewer.
|
||||||
|
- **FEAT**: remove gizmo view references, exclude gizmo entities from picking, add createIbl.
|
||||||
|
- **FEAT**: set stencil highlight on gizmo attach.
|
||||||
|
- **FEAT**: add getAncestor method.
|
||||||
|
- **FEAT**: expose API methods for create_ibl, pick/set gizmo visibility.
|
||||||
|
- **FEAT**: create transparent overlay for gizmo for easier picking.
|
||||||
|
- **FEAT**: rescale gizmo based on distance from camera.
|
||||||
|
- **FEAT**: rescale gizmo based on distance from camera.
|
||||||
|
- **FEAT**: add getAncestor method.
|
||||||
|
- **FEAT**: add startOffset parameter to gltf playAnimation.
|
||||||
|
- **FEAT**: layers, grid.
|
||||||
|
- **FEAT**: layers, grid.
|
||||||
|
- **FEAT**: ignore grid overlay and gizmo center when picking, implement highlighting.
|
||||||
|
- **FEAT**: SceneManager updates (setLayer, add grid, queueRelativePositionUpdateWorld.
|
||||||
|
- **FEAT**: expose set_layer_enabled, get_camera_fov and queue_relative_position_updateg_world_axis to ThermionDartApi.h.
|
||||||
|
- **FEAT**: add getCameraFov to FilamentViewer.
|
||||||
|
- **FEAT**: add new grid overlay files to web CmakeLists.
|
||||||
|
- **FEAT**: re-implement (native) Gizmo class, expose preserveScaling parameter for setParent, add methods for getting viewport bounding box from renderable entity.
|
||||||
|
- **FEAT**: expose setLayerEnabled, viewportDimensions and getCameraFov on ThermionView.
|
||||||
|
- **FEAT**: download WASM module directly on web (no need to embed in index.html any more) and expose updateViewportAndCameraProjection.
|
||||||
|
- **FEAT**: add capture() function and expose viewportDimensions on ThermionViewer (allows easier saving of captured images to PNG).
|
||||||
|
- **FEAT**: (web) allow table growth in emscripten module for passing C-style callback function pointers.
|
||||||
|
- **FEAT**: (web) add capture() method and missing camera navigation controls.
|
||||||
|
- **FEAT**: createIbl.
|
||||||
|
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||||
|
- **BREAKING** **FEAT**: update web/http dependencies.
|
||||||
|
|
||||||
|
#### `thermion_flutter` - `v0.2.0-dev.1.0`
|
||||||
|
|
||||||
|
- **FIX**: (flutter) pass ThermionFlutterOptions to ThermionWidget, use dpr for resizeTexture, delete unnecessary TransparencyPainter class.
|
||||||
|
- **FIX**: (flutter/web) use window.devicePixelRatio for viewport.
|
||||||
|
- **FIX**: (flutter) desktop gesture detector changes for new Gizmo methods.
|
||||||
|
- **FEAT**: allow passing null options to ThermionWidget.
|
||||||
|
- **FEAT**: (flutter) (web) if importCanvasAsWidget is false, render transparency.
|
||||||
|
- **FEAT**: add createViewerWithOptions to ThermionFlutterPlugin and mark createViewer as deprecated.
|
||||||
|
- **FEAT**: add createViewerWithOptions to ThermionFlutterPlugin and mark createViewer as deprecated.
|
||||||
|
- **FEAT**: highlight gizmo on hover.
|
||||||
|
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||||
|
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||||
|
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||||
|
- **BREAKING** **FEAT**: resize canvas on web.
|
||||||
|
- **BREAKING** **CHORE**: rename controller to viewer in gesture detector widgets.
|
||||||
|
|
||||||
|
#### `thermion_flutter_ffi` - `v0.2.0-dev.1.0`
|
||||||
|
|
||||||
|
- **FEAT**: (flutter) move DPR calculation to resizeTexture and add createViewerWithOptions method to ThermionFlutterFFI.
|
||||||
|
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||||
|
|
||||||
|
#### `thermion_flutter_platform_interface` - `v0.2.0-dev.1.0`
|
||||||
|
|
||||||
|
- **FEAT**: add createViewerWithOptions to ThermionFlutterPlugin and mark createViewer as deprecated.
|
||||||
|
- **FEAT**: add ThermionFlutterOptions classes, rename interface parameter for offsetTop and ensure pixelRatio is passed to resizeTexture.
|
||||||
|
- **BREAKING** **FIX**: (flutter) pass pixelRatio to createTexture.
|
||||||
|
|
||||||
|
#### `thermion_flutter_web` - `v0.1.0-dev.1.0`
|
||||||
|
|
||||||
|
- **FIX**: (flutter/web) use window.devicePixelRatio for viewport.
|
||||||
|
- **FEAT**: (flutter) (web) use options to determine whether to create canvas, and set fixed position + offset.
|
||||||
|
- **FEAT**: add ThermionFlutterOptions classes, rename interface parameter for offsetTop and ensure pixelRatio is passed to resizeTexture.
|
||||||
|
- **BREAKING** **FEAT**: (flutter) (web) upgrade package:web dep to 1.0.0.
|
||||||
|
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||||
|
- **BREAKING** **FEAT**: resize canvas on web.
|
||||||
|
|
||||||
|
|
||||||
## 2024-07-23
|
## 2024-07-23
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
|||||||
11
Makefile
11
Makefile
@@ -22,10 +22,13 @@ bindings:
|
|||||||
#
|
#
|
||||||
materials: FORCE
|
materials: FORCE
|
||||||
@echo "Using Filament build from ${FILAMENT_PATH}"
|
@echo "Using Filament build from ${FILAMENT_PATH}"
|
||||||
${FILAMENT_PATH}/matc -a opengl -a metal -o materials/image.filamat materials/image.mat
|
@for material in unlit image gizmo grid; do \
|
||||||
$(FILAMENT_PATH)/resgen -c -p image -x ios/include/material/ materials/image.filamat
|
${FILAMENT_PATH}/matc -a opengl -a metal -o materials/$$material.filamat materials/$$material.mat; \
|
||||||
$(FILAMENT_PATH)/matc -a opengl -a metal -o materials/gizmo.filamat materials/gizmo.mat
|
$(FILAMENT_PATH)/resgen -c -p $$material -x thermion_dart/native/include/material/ materials/$$material.filamat; \
|
||||||
$(FILAMENT_PATH)/resgen -c -p gizmo -x ios/include/material/ materials/gizmo.filamat
|
echo '#include "'$$material'.h"' | cat - thermion_dart/native/include/material/$$material.c > thermion_dart/native/include/material/$$material.c.new; \
|
||||||
|
mv thermion_dart/native/include/material/$$material.c.new thermion_dart/native/include/material/$$material.c; \
|
||||||
|
done
|
||||||
|
|
||||||
#rm materials/*.filamat
|
#rm materials/*.filamat
|
||||||
|
|
||||||
FORCE: ;
|
FORCE: ;
|
||||||
|
|||||||
@@ -6,6 +6,13 @@ A custom DartPad that lets you experiment with Thermion from your browser (curre
|
|||||||
|
|
||||||
[](https://dartpad.thermion.dev)
|
[](https://dartpad.thermion.dev)
|
||||||
|
|
||||||
|
## mixreel (Flutter/Web)
|
||||||
|
|
||||||
|
Create 3D worlds and translate to AI video.
|
||||||
|
|
||||||
|
[](https://mixreel.ai)
|
||||||
|
|
||||||
|
|
||||||
## Nick Fisher
|
## Nick Fisher
|
||||||
|
|
||||||
My personal website, where I create an interactive clone of myself with Avaturn & Cartesia (no Flutter, made with Thermion and the [Jaspr Dart UI framework](https://github.com/schultek/jaspr)).
|
My personal website, where I create an interactive clone of myself with Avaturn & Cartesia (no Flutter, made with Thermion and the [Jaspr Dart UI framework](https://github.com/schultek/jaspr)).
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:14a484a441dacbc49ce6b8b189a8900a7bb2ab2072731a3a493676aa046b5888
|
|
||||||
size 1009
|
|
||||||
@@ -1,3 +1,50 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
material {
|
||||||
oid sha256:3158461d081f058dcb9582ce19cc2daedc73abbe758ba5094c94df89028d8c4d
|
name : Gizmo,
|
||||||
size 981
|
parameters : [
|
||||||
|
{
|
||||||
|
type : mat4,
|
||||||
|
name : transform,
|
||||||
|
precision : high
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : float4,
|
||||||
|
name : color,
|
||||||
|
precision : low
|
||||||
|
}
|
||||||
|
],
|
||||||
|
depthWrite : true,
|
||||||
|
depthCulling : false,
|
||||||
|
shadingModel : unlit,
|
||||||
|
blending: transparent,
|
||||||
|
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||||
|
culling: none,
|
||||||
|
instanced: false,
|
||||||
|
vertexDomain: object
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex {
|
||||||
|
void materialVertex(inout MaterialVertexInputs material) {
|
||||||
|
|
||||||
|
// we want to ensure the gizmo has the same size (in screen-space), no matter the distance from the camera
|
||||||
|
// we do this by scaling the model-space vertex positions by the distance from the camera
|
||||||
|
vec4 modelSpace = getPosition();
|
||||||
|
vec4 worldSpace = getWorldFromModelMatrix() * modelSpace;
|
||||||
|
vec4 viewSpace = getViewFromWorldMatrix() * worldSpace;
|
||||||
|
float distanceFromCamera = length(viewSpace.xyz);
|
||||||
|
modelSpace.xyz *= (distanceFromCamera / 4.0f); // divide by 4 so that the size is equivalent to the camera being 4 world-space units away from the (unscaled) gizmo
|
||||||
|
|
||||||
|
worldSpace = getWorldFromModelMatrix() * modelSpace;
|
||||||
|
material.worldPosition = worldSpace;
|
||||||
|
//vec4 clipSpace = getClipFromWorldMatrix() * worldSpace;
|
||||||
|
//clipSpace.z = 0.99f;
|
||||||
|
//material.worldPosition = getWorldFromClipMatrix() * clipSpace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment {
|
||||||
|
void material(inout MaterialInputs material) {
|
||||||
|
prepareMaterial(material);
|
||||||
|
material.baseColor = materialParams.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
53
materials/grid.mat
Normal file
53
materials/grid.mat
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
material {
|
||||||
|
name : Grid,
|
||||||
|
parameters : [
|
||||||
|
{
|
||||||
|
type : float,
|
||||||
|
name : maxDistance
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : float3,
|
||||||
|
name : color
|
||||||
|
}
|
||||||
|
],
|
||||||
|
depthWrite : true,
|
||||||
|
depthCulling : false,
|
||||||
|
shadingModel : unlit,
|
||||||
|
blending: transparent,
|
||||||
|
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||||
|
culling: none,
|
||||||
|
instanced: false,
|
||||||
|
vertexDomain: object
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex {
|
||||||
|
void materialVertex(inout MaterialVertexInputs material) {
|
||||||
|
material.worldPosition = getWorldFromModelMatrix() * getPosition();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment {
|
||||||
|
void material(inout MaterialInputs material) {
|
||||||
|
prepareMaterial(material);
|
||||||
|
|
||||||
|
// Convert world position to view space
|
||||||
|
float4 viewPos = getViewFromWorldMatrix() * float4(getWorldPosition(), 1.0);
|
||||||
|
|
||||||
|
// Calculate distance in view space (camera is at 0,0,0 in view space)
|
||||||
|
float distance = length(viewPos.xz);
|
||||||
|
|
||||||
|
// Discard fragment if it's too far from the camera
|
||||||
|
if (distance > materialParams.maxDistance) {
|
||||||
|
material.baseColor = float4(0.0);
|
||||||
|
} else {
|
||||||
|
material.baseColor = float4(materialParams.color, 1.0);
|
||||||
|
|
||||||
|
// Optional: fade out as we approach maxDistance
|
||||||
|
float fadeStart = materialParams.maxDistance * 0.8;
|
||||||
|
if (distance > fadeStart) {
|
||||||
|
float fade = 1.0 - (distance - fadeStart) / (materialParams.maxDistance - fadeStart);
|
||||||
|
material.baseColor.a = fade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,52 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
material {
|
||||||
oid sha256:273059c97f96c6848807914d937583864445b51d8e0f1cd98c3e4e0e4bd9f411
|
name : Image,
|
||||||
size 1451
|
parameters : [
|
||||||
|
{
|
||||||
|
type : sampler2d,
|
||||||
|
name : image
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : mat4,
|
||||||
|
name : transform,
|
||||||
|
precision : high
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : float4,
|
||||||
|
name : backgroundColor
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : int,
|
||||||
|
name : showImage
|
||||||
|
}
|
||||||
|
],
|
||||||
|
variables : [
|
||||||
|
imageUV
|
||||||
|
],
|
||||||
|
vertexDomain : device,
|
||||||
|
depthWrite : false,
|
||||||
|
shadingModel : unlit,
|
||||||
|
variantFilter : [ skinning, shadowReceiver, vsm ],
|
||||||
|
culling: none
|
||||||
|
}
|
||||||
|
|
||||||
|
vertex {
|
||||||
|
void materialVertex(inout MaterialVertexInputs material) {
|
||||||
|
material.imageUV.st = getPosition().st * 0.5 + 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment {
|
||||||
|
void material(inout MaterialInputs material) {
|
||||||
|
prepareMaterial(material);
|
||||||
|
highp vec2 uv = (materialParams.transform * vec4(saturate(variable_imageUV.st), 1.0, 1.0)).st;
|
||||||
|
if (materialParams.showImage == 0 || uv.s > 1.0 || uv.s < 0.0 || uv.t < 0.0 || uv.t > 1.0) {
|
||||||
|
material.baseColor = materialParams.backgroundColor;
|
||||||
|
} else {
|
||||||
|
uv.t = 1.0 - uv.t;
|
||||||
|
vec4 color = max(texture(materialParams_image, uv.st), 0.0);
|
||||||
|
color.rgb *= color.a;
|
||||||
|
// Manual, pre-multiplied srcOver with opaque destination optimization
|
||||||
|
material.baseColor.rgb = color.rgb + materialParams.backgroundColor.rgb * (1.0 - color.a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
38
materials/unlit.mat
Normal file
38
materials/unlit.mat
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
material {
|
||||||
|
name : unlit,
|
||||||
|
requires : [ uv0 ],
|
||||||
|
parameters : [
|
||||||
|
{
|
||||||
|
type : sampler2d,
|
||||||
|
name : baseColorMap
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : float4,
|
||||||
|
name : baseColorFactor
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type : int,
|
||||||
|
name : baseColorIndex
|
||||||
|
}
|
||||||
|
],
|
||||||
|
depthWrite : true,
|
||||||
|
depthCulling : true,
|
||||||
|
shadingModel : unlit,
|
||||||
|
blending: opaque,
|
||||||
|
culling: none,
|
||||||
|
instanced: false,
|
||||||
|
vertexDomain: object
|
||||||
|
}
|
||||||
|
|
||||||
|
fragment {
|
||||||
|
void material(inout MaterialInputs material) {
|
||||||
|
prepareMaterial(material);
|
||||||
|
material.baseColor = materialParams.baseColorFactor;
|
||||||
|
|
||||||
|
if (materialParams.baseColorIndex > -1) {
|
||||||
|
highp float2 uv = getUV0();
|
||||||
|
uv.y = 1.0 - uv.y;
|
||||||
|
material.baseColor *= texture(materialParams_baseColorMap, uv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
|
||||||
oid sha256:4abb9e737d20956cced366af6a54dd31ab17cc8d0d1773f02c57a5712760fe10
|
|
||||||
size 7385
|
|
||||||
@@ -1,3 +1,55 @@
|
|||||||
|
## 0.2.0-dev.1.0
|
||||||
|
|
||||||
|
> Note: This release has breaking changes.
|
||||||
|
|
||||||
|
- **REFACTOR**: native types.
|
||||||
|
- **REFACTOR**: native types.
|
||||||
|
- **REFACTOR**: move native types to own header, add methods for create/destroy material instance, add priority/layer to load_glb_from_buffer.
|
||||||
|
- **REFACTOR**: Dart types.
|
||||||
|
- **FIX**: (web) add emscripten guards for flushAndWait call when swapchain destroyed.
|
||||||
|
- **FIX**: ignore pick results directly on axis.
|
||||||
|
- **FIX**: properly destroy entities/material/etc in Gizmo on destruction, remove custom scene creation logic.
|
||||||
|
- **FIX**: add check for nan NDC coordinates for viewport translation.
|
||||||
|
- **FIX**: (wasm) use correct coords for pick, free memory correctly, keep pixelratio copy.
|
||||||
|
- **FIX**: add more nan checks for gizmo manipulation.
|
||||||
|
- **FIX**: emscripten export visibility for add_light.
|
||||||
|
- **FIX**: add Fence to capture() and set stencil buffer by default.
|
||||||
|
- **FEAT**: add removeStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionViewer.
|
||||||
|
- **FEAT**: add removeStencilHighlight, accept color param for setStencilHighlight, queuePositionUpdateFromViewportCoords to ThermionDartApi.
|
||||||
|
- **FEAT**: add flag for keepData for gltf instancing, add highlightScene, add stencilHighlight method.
|
||||||
|
- **FEAT**: grid uses own material.
|
||||||
|
- **FEAT**: parent the cloned entity instance when setting stencil highlight.
|
||||||
|
- **FEAT**: add grid material.
|
||||||
|
- **FEAT**: expose setLightDirection and setLightPosition.
|
||||||
|
- **FEAT**: move HighlightOverlay to nested class, move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector.
|
||||||
|
- **FEAT**: move createGeometry to SceneManager, add queueRelativePositionUpdateFromViewportVector and removeStencilHighlight.
|
||||||
|
- **FEAT**: add setGizmoVisibility/pickGizmo methods to ThermionViewer.
|
||||||
|
- **FEAT**: remove gizmo view references, exclude gizmo entities from picking, add createIbl.
|
||||||
|
- **FEAT**: set stencil highlight on gizmo attach.
|
||||||
|
- **FEAT**: add getAncestor method.
|
||||||
|
- **FEAT**: expose API methods for create_ibl, pick/set gizmo visibility.
|
||||||
|
- **FEAT**: create transparent overlay for gizmo for easier picking.
|
||||||
|
- **FEAT**: rescale gizmo based on distance from camera.
|
||||||
|
- **FEAT**: rescale gizmo based on distance from camera.
|
||||||
|
- **FEAT**: add getAncestor method.
|
||||||
|
- **FEAT**: add startOffset parameter to gltf playAnimation.
|
||||||
|
- **FEAT**: layers, grid.
|
||||||
|
- **FEAT**: layers, grid.
|
||||||
|
- **FEAT**: ignore grid overlay and gizmo center when picking, implement highlighting.
|
||||||
|
- **FEAT**: SceneManager updates (setLayer, add grid, queueRelativePositionUpdateWorld.
|
||||||
|
- **FEAT**: expose set_layer_enabled, get_camera_fov and queue_relative_position_updateg_world_axis to ThermionDartApi.h.
|
||||||
|
- **FEAT**: add getCameraFov to FilamentViewer.
|
||||||
|
- **FEAT**: add new grid overlay files to web CmakeLists.
|
||||||
|
- **FEAT**: re-implement (native) Gizmo class, expose preserveScaling parameter for setParent, add methods for getting viewport bounding box from renderable entity.
|
||||||
|
- **FEAT**: expose setLayerEnabled, viewportDimensions and getCameraFov on ThermionView.
|
||||||
|
- **FEAT**: download WASM module directly on web (no need to embed in index.html any more) and expose updateViewportAndCameraProjection.
|
||||||
|
- **FEAT**: add capture() function and expose viewportDimensions on ThermionViewer (allows easier saving of captured images to PNG).
|
||||||
|
- **FEAT**: (web) allow table growth in emscripten module for passing C-style callback function pointers.
|
||||||
|
- **FEAT**: (web) add capture() method and missing camera navigation controls.
|
||||||
|
- **FEAT**: createIbl.
|
||||||
|
- **BREAKING** **FEAT**: (web) (flutter) create canvas when createViewer is called (no longer need to manually add canvas element to web HTML).
|
||||||
|
- **BREAKING** **FEAT**: update web/http dependencies.
|
||||||
|
|
||||||
## 0.1.3
|
## 0.1.3
|
||||||
|
|
||||||
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
- **FIX**: manually remove leading slash for compiler path on Windows when building for Android.
|
||||||
|
|||||||
@@ -1,13 +1,19 @@
|
|||||||
output: '../lib/thermion_dart/compatibility/native/thermion_dart.g.dart'
|
output: '../lib/thermion_dart/viewer/ffi/thermion_dart.g.dart'
|
||||||
headers:
|
headers:
|
||||||
entry-points:
|
entry-points:
|
||||||
- '../native/include/ThermionDartFFIApi.h'
|
- '../native/include/ThermionDartRenderThreadApi.h'
|
||||||
- '../native/include/ThermionDartApi.h'
|
- '../native/include/ThermionDartApi.h'
|
||||||
- '../native/include/ResourceBuffer.h'
|
- '../native/include/ResourceBuffer.h'
|
||||||
include-directives:
|
include-directives:
|
||||||
- '../native/include/ThermionDartFFIApi.h'
|
- '../native/include/ThermionDartRenderThreadApi.h'
|
||||||
- '../native/include/ThermionDartApi.h'
|
- '../native/include/ThermionDartApi.h'
|
||||||
- '../native/include/ResourceBuffer.h'
|
- '../native/include/ResourceBuffer.h'
|
||||||
|
- '../native/include/APIBoundaryTypes.h'
|
||||||
ffi-native:
|
ffi-native:
|
||||||
assetId: package:thermion_dart/thermion_dart.dart
|
assetId: package:thermion_dart/thermion_dart.dart
|
||||||
ignore-source-errors: true
|
ignore-source-errors: true
|
||||||
|
functions:
|
||||||
|
leaf:
|
||||||
|
include:
|
||||||
|
- '.*'
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ void main(List<String> args) async {
|
|||||||
sources.addAll([
|
sources.addAll([
|
||||||
"${config.packageRoot.toFilePath()}/native/include/material/gizmo.c",
|
"${config.packageRoot.toFilePath()}/native/include/material/gizmo.c",
|
||||||
"${config.packageRoot.toFilePath()}/native/include/material/image.c",
|
"${config.packageRoot.toFilePath()}/native/include/material/image.c",
|
||||||
|
"${config.packageRoot.toFilePath()}/native/include/material/grid.c",
|
||||||
|
"${config.packageRoot.toFilePath()}/native/include/material/unlit.c",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var libs = [
|
var libs = [
|
||||||
@@ -76,7 +78,6 @@ void main(List<String> args) async {
|
|||||||
"image",
|
"image",
|
||||||
"imageio",
|
"imageio",
|
||||||
"tinyexr",
|
"tinyexr",
|
||||||
"gltfio_core",
|
|
||||||
"filaflat",
|
"filaflat",
|
||||||
"dracodec",
|
"dracodec",
|
||||||
"ibl",
|
"ibl",
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
library filament_dart;
|
library filament_dart;
|
||||||
|
|
||||||
export 'thermion_dart/thermion_viewer.dart';
|
export 'thermion_dart/thermion_viewer.dart';
|
||||||
export 'thermion_dart/thermion_viewer_stub.dart'
|
|
||||||
if (dart.library.io) 'thermion_dart/thermion_viewer_ffi.dart'
|
|
||||||
if (dart.library.js_interop)'thermion_dart/compatibility/web/interop/thermion_viewer_wasm.dart';
|
|
||||||
|
|
||||||
export 'thermion_dart/entities/entity_transform_controller.dart';
|
export 'thermion_dart/entities/entity_transform_controller.dart';
|
||||||
|
export 'thermion_dart/utils/geometry.dart';
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export 'native/compatibility.dart';
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,238 +0,0 @@
|
|||||||
import 'dart:ffi';
|
|
||||||
export "allocator.dart";
|
|
||||||
export "thermion_dart.g.dart";
|
|
||||||
|
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:ffi' as ffi hide Uint8Pointer, FloatPointer;
|
|
||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/web/ffi/thermion_dart.g.dart';
|
|
||||||
|
|
||||||
import 'package:ffi/ffi.dart';
|
|
||||||
export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer;
|
|
||||||
export 'dart:ffi'
|
|
||||||
hide
|
|
||||||
Uint8Pointer,
|
|
||||||
FloatPointer,
|
|
||||||
DoublePointer,
|
|
||||||
Int32Pointer,
|
|
||||||
Int64Pointer,
|
|
||||||
PointerPointer,
|
|
||||||
Allocator;
|
|
||||||
|
|
||||||
class Allocator implements ffi.Allocator {
|
|
||||||
const Allocator();
|
|
||||||
@override
|
|
||||||
ffi.Pointer<T> allocate<T extends ffi.NativeType>(int byteCount,
|
|
||||||
{int? alignment}) {
|
|
||||||
return thermion_flutter_web_allocate(byteCount).cast<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void free(ffi.Pointer<ffi.NativeType> pointer) {
|
|
||||||
thermion_flutter_web_free(pointer.cast<ffi.Void>());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension CharPointer on ffi.Pointer<ffi.Char> {
|
|
||||||
int get value {
|
|
||||||
return thermion_flutter_web_get(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(int value) {
|
|
||||||
thermion_flutter_web_set(this, 0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, int value) {
|
|
||||||
this.elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Char> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Char>() * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension IntPointer on ffi.Pointer<ffi.Int> {
|
|
||||||
int get value {
|
|
||||||
return thermion_flutter_web_get_int32(this.cast<ffi.Int32>(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(int value) {
|
|
||||||
thermion_flutter_web_set_int32(this.cast<ffi.Int32>(), 0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, int value) {
|
|
||||||
this.elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int operator [](int index) {
|
|
||||||
return this.elementAt(index).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Int> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Int>() * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension Int32Pointer on ffi.Pointer<ffi.Int32> {
|
|
||||||
int get value {
|
|
||||||
return thermion_flutter_web_get_int32(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(int value) {
|
|
||||||
thermion_flutter_web_set_int32(this, 0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, int value) {
|
|
||||||
this.elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int operator [](int index) {
|
|
||||||
return this.elementAt(index).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Int32> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Int32>() * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension UInt8Pointer on ffi.Pointer<ffi.Uint8> {
|
|
||||||
int get value {
|
|
||||||
return thermion_flutter_web_get(this.cast<ffi.Char>(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(int value) {
|
|
||||||
thermion_flutter_web_set(this.cast<ffi.Char>(), 0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, int value) {
|
|
||||||
this.elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int operator [](int index) {
|
|
||||||
return this.elementAt(index).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Uint8> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Uint8>() * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension PointerPointer<T extends ffi.NativeType>
|
|
||||||
on ffi.Pointer<ffi.Pointer<T>> {
|
|
||||||
ffi.Pointer<T> get value {
|
|
||||||
return thermion_flutter_web_get_pointer(cast<ffi.Pointer<ffi.Void>>(), 0)
|
|
||||||
.cast<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(ffi.Pointer<T> value) {
|
|
||||||
thermion_flutter_web_set_pointer(
|
|
||||||
cast<ffi.Pointer<ffi.Void>>(), 0, value.cast<ffi.Void>());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ffi.Pointer<T> operator [](int index) {
|
|
||||||
return this.elementAt(index).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, ffi.Pointer<T> value) {
|
|
||||||
this.elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Pointer<T>> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Pointer>() * index);
|
|
||||||
}
|
|
||||||
|
|
||||||
extension FloatPointer on ffi.Pointer<ffi.Float> {
|
|
||||||
double get value {
|
|
||||||
return thermion_flutter_web_get_float(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(double value) {
|
|
||||||
thermion_flutter_web_set_float(this, 0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
double operator [](int index) {
|
|
||||||
return this.elementAt(index).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, double value) {
|
|
||||||
this.elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Float> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Float>() * index);
|
|
||||||
|
|
||||||
Float32List asTypedList(int length) {
|
|
||||||
var list = Float32List(length);
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
list[i] = this[i];
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension StringConversion on String {
|
|
||||||
ffi.Pointer<Utf8> toNativeUtf8({ffi.Allocator? allocator}) {
|
|
||||||
final units = utf8.encode(this);
|
|
||||||
final ffi.Pointer<ffi.Uint8> result =
|
|
||||||
allocator!<ffi.Uint8>(units.length + 1);
|
|
||||||
for (int i = 0; i < units.length; i++) {
|
|
||||||
result.elementAt(i).value = units[i];
|
|
||||||
}
|
|
||||||
result.elementAt(units.length).value = 0;
|
|
||||||
return result.cast();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension StringUtf8Pointer on ffi.Pointer<Utf8> {
|
|
||||||
static int _length(ffi.Pointer<ffi.Uint8> codeUnits) {
|
|
||||||
var length = 0;
|
|
||||||
while (codeUnits[length] != 0) {
|
|
||||||
length++;
|
|
||||||
}
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
String toDartString({int? length}) {
|
|
||||||
final codeUnits = this.cast<ffi.Uint8>();
|
|
||||||
final list = <int>[];
|
|
||||||
|
|
||||||
if (length != null) {
|
|
||||||
RangeError.checkNotNegative(length, 'length');
|
|
||||||
} else {
|
|
||||||
length = _length(codeUnits);
|
|
||||||
}
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
list.add(codeUnits.elementAt(i).value);
|
|
||||||
}
|
|
||||||
return utf8.decode(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extension DoublePointer on ffi.Pointer<ffi.Double> {
|
|
||||||
double get value {
|
|
||||||
return thermion_flutter_web_get_double(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
set value(double value) {
|
|
||||||
return thermion_flutter_web_set_double(this, 0, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Float64List asTypedList(int length) {
|
|
||||||
var list = Float64List(length);
|
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
list[i] = elementAt(i).value;
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
double operator [](int index) {
|
|
||||||
return elementAt(index).value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator []=(int index, double value) {
|
|
||||||
elementAt(index).value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
ffi.Pointer<ffi.Double> elementAt(int index) =>
|
|
||||||
ffi.Pointer.fromAddress(address + ffi.sizeOf<ffi.Double>() * index);
|
|
||||||
}
|
|
||||||
@@ -1,118 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'dart:js_interop';
|
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/web/ffi/interop.dart';
|
|
||||||
|
|
||||||
import "allocator.dart";
|
|
||||||
|
|
||||||
export "allocator.dart";
|
|
||||||
export "thermion_dart.g.dart";
|
|
||||||
|
|
||||||
export 'package:ffi/ffi.dart' hide StringUtf8Pointer, Utf8Pointer;
|
|
||||||
export 'dart:ffi'
|
|
||||||
hide
|
|
||||||
Uint8Pointer,
|
|
||||||
FloatPointer,
|
|
||||||
DoublePointer,
|
|
||||||
Int32Pointer,
|
|
||||||
Int64Pointer,
|
|
||||||
PointerPointer,
|
|
||||||
Allocator;
|
|
||||||
|
|
||||||
const allocator = Allocator();
|
|
||||||
|
|
||||||
@AbiSpecificIntegerMapping({
|
|
||||||
Abi.androidArm: Uint8(),
|
|
||||||
Abi.androidArm64: Uint8(),
|
|
||||||
Abi.androidIA32: Int8(),
|
|
||||||
Abi.androidX64: Int8(),
|
|
||||||
Abi.androidRiscv64: Uint8(),
|
|
||||||
Abi.fuchsiaArm64: Uint8(),
|
|
||||||
Abi.fuchsiaX64: Int8(),
|
|
||||||
Abi.fuchsiaRiscv64: Uint8(),
|
|
||||||
Abi.iosArm: Int8(),
|
|
||||||
Abi.iosArm64: Int8(),
|
|
||||||
Abi.iosX64: Int8(),
|
|
||||||
Abi.linuxArm: Uint8(),
|
|
||||||
Abi.linuxArm64: Uint8(),
|
|
||||||
Abi.linuxIA32: Int8(),
|
|
||||||
Abi.linuxX64: Int8(),
|
|
||||||
Abi.linuxRiscv32: Uint8(),
|
|
||||||
Abi.linuxRiscv64: Uint8(),
|
|
||||||
Abi.macosArm64: Int8(),
|
|
||||||
Abi.macosX64: Int8(),
|
|
||||||
Abi.windowsArm64: Int8(),
|
|
||||||
Abi.windowsIA32: Int8(),
|
|
||||||
Abi.windowsX64: Int8(),
|
|
||||||
})
|
|
||||||
final class FooChar extends AbiSpecificInteger {
|
|
||||||
const FooChar();
|
|
||||||
}
|
|
||||||
|
|
||||||
class Compatibility {
|
|
||||||
final _foo = FooChar();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> withVoidCallback(
|
|
||||||
Function(Pointer<NativeFunction<Void Function()>>) func) async {
|
|
||||||
JSArray retVal = createVoidCallback();
|
|
||||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
|
||||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
|
||||||
var fnPtr = Pointer<NativeFunction<Void Function()>>.fromAddress(
|
|
||||||
fnPtrAddress.toDartInt);
|
|
||||||
func(fnPtr);
|
|
||||||
await promise.toDart;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> withVoidPointerCallback(
|
|
||||||
void Function(Pointer<NativeFunction<Void Function(Pointer<Void>)>>)
|
|
||||||
func) async {
|
|
||||||
JSArray retVal = createVoidPointerCallback();
|
|
||||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
|
||||||
|
|
||||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
|
||||||
var fnPtr = Pointer<NativeFunction<Void Function(Pointer<Void>)>>.fromAddress(
|
|
||||||
fnPtrAddress.toDartInt);
|
|
||||||
func(fnPtr);
|
|
||||||
final addr = await promise.toDart;
|
|
||||||
return addr.toDartInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<bool> withBoolCallback(
|
|
||||||
Function(Pointer<NativeFunction<Void Function(Bool)>>) func) async {
|
|
||||||
JSArray retVal = createBoolCallback();
|
|
||||||
var promise = retVal.toDart[0] as JSPromise<JSBoolean>;
|
|
||||||
|
|
||||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
|
||||||
var fnPtr = Pointer<NativeFunction<Void Function(Bool)>>.fromAddress(
|
|
||||||
fnPtrAddress.toDartInt);
|
|
||||||
func(fnPtr);
|
|
||||||
final addr = await promise.toDart;
|
|
||||||
return addr.toDart;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<int> withIntCallback(
|
|
||||||
Function(Pointer<NativeFunction<Void Function(Int32)>>) func) async {
|
|
||||||
JSArray retVal = createBoolCallback();
|
|
||||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
|
||||||
|
|
||||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
|
||||||
var fnPtr = Pointer<NativeFunction<Void Function(Int32)>>.fromAddress(
|
|
||||||
fnPtrAddress.toDartInt);
|
|
||||||
func(fnPtr);
|
|
||||||
final addr = await promise.toDart;
|
|
||||||
return addr.toDartInt;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<String> withCharPtrCallback(
|
|
||||||
Function(Pointer<NativeFunction<Void Function(Pointer<Char>)>>)
|
|
||||||
func) async {
|
|
||||||
JSArray retVal = createVoidPointerCallback();
|
|
||||||
var promise = retVal.toDart[0] as JSPromise<JSNumber>;
|
|
||||||
|
|
||||||
var fnPtrAddress = retVal.toDart[1] as JSNumber;
|
|
||||||
var fnPtr = Pointer<NativeFunction<Void Function(Pointer<Char>)>>.fromAddress(
|
|
||||||
fnPtrAddress.toDartInt);
|
|
||||||
func(fnPtr);
|
|
||||||
final addr = await promise.toDart;
|
|
||||||
return Pointer<Utf8>.fromAddress(addr.toDartInt).toDartString();
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import 'dart:js_interop';
|
|
||||||
|
|
||||||
@JS()
|
|
||||||
external JSArray createIntCallback();
|
|
||||||
|
|
||||||
@JS()
|
|
||||||
external JSArray createBoolCallback();
|
|
||||||
|
|
||||||
@JS()
|
|
||||||
external JSArray createVoidPointerCallback();
|
|
||||||
|
|
||||||
@JS()
|
|
||||||
external JSArray createVoidCallback();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,20 @@
|
|||||||
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
|
abstract class AbstractGizmo {
|
||||||
|
|
||||||
|
bool get isVisible;
|
||||||
|
bool get isHovered;
|
||||||
|
|
||||||
|
Future translate(double transX, double transY);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
Future attach(ThermionEntity entity);
|
||||||
|
|
||||||
|
Future detach();
|
||||||
|
|
||||||
|
Stream<Aabb2> get boundingBox;
|
||||||
|
|
||||||
|
void checkHover(double x, double y);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,46 +1,68 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
import '../thermion_viewer.dart';
|
import '../thermion_viewer.dart';
|
||||||
|
|
||||||
class Gizmo extends AbstractGizmo {
|
class Gizmo extends AbstractGizmo {
|
||||||
final ThermionEntity x;
|
final ThermionEntity x;
|
||||||
Vector3 _x = Vector3(0.1, 0, 0);
|
|
||||||
final ThermionEntity y;
|
final ThermionEntity y;
|
||||||
Vector3 _y = Vector3(0.0, 0.1, 0);
|
|
||||||
final ThermionEntity z;
|
final ThermionEntity z;
|
||||||
Vector3 _z = Vector3(0.0, 0.0, 0.1);
|
final ThermionEntity center;
|
||||||
|
|
||||||
final ThermionViewer controller;
|
final ThermionViewer _viewer;
|
||||||
|
|
||||||
ThermionEntity? _activeAxis;
|
ThermionEntity? _activeAxis;
|
||||||
ThermionEntity? _activeEntity;
|
ThermionEntity? _activeEntity;
|
||||||
bool get isActive => _activeAxis != null;
|
|
||||||
|
bool _visible = false;
|
||||||
|
bool get isVisible => _visible;
|
||||||
|
|
||||||
|
bool _isHovered = false;
|
||||||
|
bool get isHovered => _isHovered;
|
||||||
|
|
||||||
final Set<ThermionEntity> ignore;
|
final Set<ThermionEntity> ignore;
|
||||||
|
|
||||||
Gizmo(this.x, this.y, this.z, this.controller,
|
Stream<Aabb2> get boundingBox => _boundingBoxController.stream;
|
||||||
|
final _boundingBoxController = StreamController<Aabb2>.broadcast();
|
||||||
|
|
||||||
|
Gizmo(this.x, this.y, this.z, this.center, this._viewer,
|
||||||
{this.ignore = const <ThermionEntity>{}}) {
|
{this.ignore = const <ThermionEntity>{}}) {
|
||||||
controller.pickResult.listen(_onPickResult);
|
_viewer.gizmoPickResult.listen(_onGizmoPickResult);
|
||||||
|
_viewer.pickResult.listen(_onPickResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future _reveal() async {
|
final _stopwatch = Stopwatch();
|
||||||
await controller.reveal(x, null);
|
|
||||||
await controller.reveal(y, null);
|
|
||||||
await controller.reveal(z, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
void translate(double transX, double transY) async {
|
double _transX = 0.0;
|
||||||
late Vector3 vec;
|
double _transY = 0.0;
|
||||||
if (_activeAxis == x) {
|
|
||||||
vec = _x;
|
Future translate(double transX, double transY) async {
|
||||||
} else if (_activeAxis == y) {
|
if (!_stopwatch.isRunning) {
|
||||||
vec = _y;
|
_stopwatch.start();
|
||||||
} else if (_activeAxis == z) {
|
|
||||||
vec = _z;
|
|
||||||
}
|
}
|
||||||
await controller.queuePositionUpdate(
|
|
||||||
_activeEntity!, transX * vec.x, -transY * vec.y, -transX * vec.z,
|
_transX += transX;
|
||||||
relative: true);
|
_transY += transY;
|
||||||
|
|
||||||
|
if (_stopwatch.elapsedMilliseconds < 16) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final axis = Vector3(_activeAxis == x ? 1.0 : 0.0,
|
||||||
|
_activeAxis == y ? 1.0 : 0.0, _activeAxis == z ? 1.0 : 0.0);
|
||||||
|
|
||||||
|
await _viewer.queueRelativePositionUpdateWorldAxis(
|
||||||
|
_activeEntity!,
|
||||||
|
_transX * _viewer.pixelRatio,
|
||||||
|
-_transY *
|
||||||
|
_viewer
|
||||||
|
.pixelRatio, // flip the sign because "up" in NDC Y axis is positive, but negative in Flutter
|
||||||
|
axis.x,
|
||||||
|
axis.y,
|
||||||
|
axis.z);
|
||||||
|
_transX = 0;
|
||||||
|
_transY = 0;
|
||||||
|
_stopwatch.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset() {
|
void reset() {
|
||||||
@@ -48,32 +70,48 @@ class Gizmo extends AbstractGizmo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onPickResult(FilamentPickResult result) async {
|
void _onPickResult(FilamentPickResult result) async {
|
||||||
if (ignore.contains(result)) {
|
await attach(result.entity);
|
||||||
detach();
|
}
|
||||||
return;
|
|
||||||
}
|
void _onGizmoPickResult(FilamentPickResult result) async {
|
||||||
if (result.entity == x || result.entity == y || result.entity == z) {
|
if (result.entity == x || result.entity == y || result.entity == z) {
|
||||||
_activeAxis = result.entity;
|
_activeAxis = result.entity;
|
||||||
|
_isHovered = true;
|
||||||
|
} else if (result.entity == 0) {
|
||||||
|
_activeAxis = null;
|
||||||
|
_isHovered = false;
|
||||||
} else {
|
} else {
|
||||||
attach(result.entity);
|
throw Exception("Unexpected gizmo pick result");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void attach(ThermionEntity entity) async {
|
Future attach(ThermionEntity entity) async {
|
||||||
_activeAxis = null;
|
_activeAxis = null;
|
||||||
|
if (entity == _activeEntity) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (entity == center) {
|
||||||
|
_activeEntity = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_visible = true;
|
||||||
|
|
||||||
|
if (_activeEntity != null) {
|
||||||
|
await _viewer.removeStencilHighlight(_activeEntity!);
|
||||||
|
}
|
||||||
_activeEntity = entity;
|
_activeEntity = entity;
|
||||||
await _reveal();
|
await _viewer.setGizmoVisibility(true);
|
||||||
await controller.setParent(x, entity);
|
await _viewer.setParent(center, entity, preserveScaling: false);
|
||||||
await controller.setParent(y, entity);
|
_boundingBoxController.sink.add(await _viewer.getViewportBoundingBox(x));
|
||||||
await controller.setParent(z, entity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void detach() async {
|
Future detach() async {
|
||||||
await controller.setParent(x, 0);
|
await _viewer.setGizmoVisibility(false);
|
||||||
await controller.setParent(y, 0);
|
}
|
||||||
await controller.setParent(z, 0);
|
|
||||||
await controller.hide(x, null);
|
@override
|
||||||
await controller.hide(y, null);
|
void checkHover(double x, double y) {
|
||||||
await controller.hide(z, null);
|
_viewer.pickGizmo(x.toInt(), y.toInt());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,48 +1,233 @@
|
|||||||
|
import 'dart:convert';
|
||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
import 'dart:async';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
///
|
class SceneV2 {
|
||||||
/// For now, this class just holds the entities that have been loaded (though not necessarily visible in the Filament Scene).
|
final Map<String, AssetInfo> assets;
|
||||||
///
|
final List<LightInfo> lights;
|
||||||
abstract class Scene {
|
List<CameraInfo> cameras;
|
||||||
///
|
final List<EntityInfo> entities;
|
||||||
/// The last entity clicked/tapped in the viewport (internally, the result of calling pick);
|
EnvironmentInfo? environment;
|
||||||
ThermionEntity? selected;
|
|
||||||
|
|
||||||
///
|
SceneV2({
|
||||||
/// A Stream updated whenever an entity is added/removed from the scene.
|
Map<String, AssetInfo>? assets,
|
||||||
///
|
List<LightInfo>? lights,
|
||||||
Stream<bool> get onUpdated;
|
List<CameraInfo>? cameras,
|
||||||
|
List<EntityInfo>? entities,
|
||||||
|
this.environment,
|
||||||
|
}) : assets = assets ?? {},
|
||||||
|
lights = lights ?? [],
|
||||||
|
cameras = cameras ?? [],
|
||||||
|
entities = entities ?? [];
|
||||||
|
|
||||||
///
|
void addAsset(String uri, AssetType type) {
|
||||||
/// A Stream containing every ThermionEntity added to the scene (i.e. via [loadGlb], [loadGltf] or [addLight]).
|
assets[uri] = AssetInfo(uri: uri, type: type);
|
||||||
/// This is provided for convenience so you can set listeners in front-end widgets that can respond to entity loads without manually passing around the ThermionEntity returned from those methods.
|
}
|
||||||
///
|
|
||||||
Stream<ThermionEntity> get onLoad;
|
|
||||||
|
|
||||||
///
|
void addLight(LightInfo light) {
|
||||||
/// A Stream containing every ThermionEntity removed from the scene (i.e. via [removeEntity], [clearEntities], [removeLight] or [clearLights]).
|
lights.add(light);
|
||||||
|
}
|
||||||
|
|
||||||
Stream<ThermionEntity> get onUnload;
|
void clearAssets() {
|
||||||
|
assets.clear();
|
||||||
|
}
|
||||||
|
|
||||||
///
|
void clearLights() {
|
||||||
/// Lists all light entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
lights.clear();
|
||||||
///
|
}
|
||||||
Iterable<ThermionEntity> listLights();
|
|
||||||
|
|
||||||
///
|
void setCamera(Matrix4 modelMatrix, Matrix4 projectionMatrix) {
|
||||||
/// Lists all entities currently loaded (not necessarily active in the scene). Does not account for instances.
|
var camera = cameras.firstWhere((cam) => cam.isActive);
|
||||||
///
|
camera.modelMatrix = modelMatrix;
|
||||||
Iterable<ThermionEntity> listEntities();
|
camera.projectionMatrix = projectionMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
void addEntity(String assetUri, Matrix4 transform) {
|
||||||
/// Attach the gizmo to the specified entity.
|
if (assets.containsKey(assetUri)) {
|
||||||
///
|
entities.add(EntityInfo(assetUri: assetUri, transform: transform));
|
||||||
void select(ThermionEntity entity);
|
} else {
|
||||||
|
throw Exception('Asset not found: $assetUri');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///
|
void setEnvironment(String? skyboxUri, String? iblUri) {
|
||||||
///
|
environment = EnvironmentInfo(skyboxUri: skyboxUri, iblUri: iblUri);
|
||||||
///
|
}
|
||||||
void registerEntity(ThermionEntity entity);
|
|
||||||
|
|
||||||
}
|
Map<String, dynamic> toJson() => {
|
||||||
|
'assets': assets.map((key, value) => MapEntry(key, value.toJson())),
|
||||||
|
'lights': lights.map((light) => light.toJson()).toList(),
|
||||||
|
'cameras': cameras.map((camera) => camera.toJson()),
|
||||||
|
'entities': entities.map((entity) => entity.toJson()).toList(),
|
||||||
|
'environment': environment?.toJson(),
|
||||||
|
};
|
||||||
|
|
||||||
|
String toJsonString() => jsonEncode(toJson());
|
||||||
|
|
||||||
|
static SceneV2 fromJson(Map<String, dynamic> json) {
|
||||||
|
return SceneV2(
|
||||||
|
assets: (json['assets'] as Map<String, dynamic>).map(
|
||||||
|
(key, value) => MapEntry(key, AssetInfo.fromJson(value)),
|
||||||
|
),
|
||||||
|
lights: (json['lights'] as List)
|
||||||
|
.map((light) => LightInfo.fromJson(light))
|
||||||
|
.toList(),
|
||||||
|
cameras: json['cameras'].map((camera) => CameraInfo.fromJson),
|
||||||
|
entities: (json['entities'] as List)
|
||||||
|
.map((entity) => EntityInfo.fromJson(entity))
|
||||||
|
.toList(),
|
||||||
|
environment: json['environment'] != null
|
||||||
|
? EnvironmentInfo.fromJson(json['environment'])
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static SceneV2 fromJsonString(String jsonString) =>
|
||||||
|
fromJson(jsonDecode(jsonString));
|
||||||
|
}
|
||||||
|
|
||||||
|
class AssetInfo {
|
||||||
|
final String uri;
|
||||||
|
final AssetType type;
|
||||||
|
|
||||||
|
AssetInfo({required this.uri, required this.type});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'uri': uri,
|
||||||
|
'type': type.toString().split('.').last,
|
||||||
|
};
|
||||||
|
|
||||||
|
static AssetInfo fromJson(Map<String, dynamic> json) {
|
||||||
|
return AssetInfo(
|
||||||
|
uri: json['uri'],
|
||||||
|
type: AssetType.values.firstWhere(
|
||||||
|
(e) => e.toString().split('.').last == json['type'],
|
||||||
|
orElse: () => AssetType.glb),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AssetType { glb, gltf, geometryPrimitive }
|
||||||
|
|
||||||
|
class LightInfo {
|
||||||
|
final LightType type;
|
||||||
|
final Vector3 position;
|
||||||
|
final Vector3 direction;
|
||||||
|
final Color color;
|
||||||
|
final double intensity;
|
||||||
|
|
||||||
|
LightInfo({
|
||||||
|
required this.type,
|
||||||
|
required this.position,
|
||||||
|
required this.direction,
|
||||||
|
required this.color,
|
||||||
|
required this.intensity,
|
||||||
|
});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'type': type.toString().split('.').last,
|
||||||
|
'position': [position.x, position.y, position.z],
|
||||||
|
'direction': [direction.x, direction.y, direction.z],
|
||||||
|
'color': color.toJson(),
|
||||||
|
'intensity': intensity,
|
||||||
|
};
|
||||||
|
|
||||||
|
static LightInfo fromJson(Map<String, dynamic> json) {
|
||||||
|
return LightInfo(
|
||||||
|
type: LightType.values.firstWhere((e) => e.name == json['type']),
|
||||||
|
position: Vector3.array(json['position'].cast<double>()),
|
||||||
|
direction: Vector3.array(json['direction'].cast<double>()),
|
||||||
|
color: Color.fromJson(json['color']),
|
||||||
|
intensity: json['intensity'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CameraInfo {
|
||||||
|
final bool isActive;
|
||||||
|
Matrix4 modelMatrix;
|
||||||
|
Matrix4 projectionMatrix;
|
||||||
|
|
||||||
|
CameraInfo(
|
||||||
|
{required this.isActive,
|
||||||
|
required this.modelMatrix,
|
||||||
|
required this.projectionMatrix});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'modelMatrix': modelMatrix.storage,
|
||||||
|
'projectionMatrix': projectionMatrix.storage,
|
||||||
|
'isActive': isActive,
|
||||||
|
};
|
||||||
|
|
||||||
|
static CameraInfo fromJson(Map<String, dynamic> json) {
|
||||||
|
return CameraInfo(
|
||||||
|
modelMatrix:
|
||||||
|
Matrix4.fromFloat64List(json['modelMatrix'].cast<double>()),
|
||||||
|
projectionMatrix:
|
||||||
|
Matrix4.fromFloat64List(json['modelMatrix'].cast<double>()),
|
||||||
|
isActive: json["isActive"]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EntityInfo {
|
||||||
|
final String assetUri;
|
||||||
|
final Matrix4 transform;
|
||||||
|
|
||||||
|
EntityInfo({required this.assetUri, required this.transform});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'assetUri': assetUri,
|
||||||
|
'transform': transform.storage,
|
||||||
|
};
|
||||||
|
|
||||||
|
static EntityInfo fromJson(Map<String, dynamic> json) {
|
||||||
|
return EntityInfo(
|
||||||
|
assetUri: json['assetUri'],
|
||||||
|
transform: Matrix4.fromList(List<double>.from(json['transform'])),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EnvironmentInfo {
|
||||||
|
final String? skyboxUri;
|
||||||
|
final String? iblUri;
|
||||||
|
|
||||||
|
EnvironmentInfo({this.skyboxUri, this.iblUri});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'skyboxUri': skyboxUri,
|
||||||
|
'iblUri': iblUri,
|
||||||
|
};
|
||||||
|
|
||||||
|
static EnvironmentInfo fromJson(Map<String, dynamic> json) {
|
||||||
|
return EnvironmentInfo(
|
||||||
|
skyboxUri: json['skyboxUri'],
|
||||||
|
iblUri: json['iblUri'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Color {
|
||||||
|
final double r;
|
||||||
|
final double g;
|
||||||
|
final double b;
|
||||||
|
final double a;
|
||||||
|
|
||||||
|
Color({required this.r, required this.g, required this.b, this.a = 1.0});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() => {
|
||||||
|
'r': r,
|
||||||
|
'g': g,
|
||||||
|
'b': b,
|
||||||
|
'a': a,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Color fromJson(Map<String, dynamic> json) {
|
||||||
|
return Color(
|
||||||
|
r: json['r'],
|
||||||
|
g: json['g'],
|
||||||
|
b: json['b'],
|
||||||
|
a: json['a'],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,125 +0,0 @@
|
|||||||
import 'dart:async';
|
|
||||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
|
||||||
import 'thermion_viewer.dart';
|
|
||||||
|
|
||||||
///
|
|
||||||
/// For now, this class just holds the entities that have been loaded (though not necessarily visible in the Filament Scene).
|
|
||||||
///
|
|
||||||
class SceneImpl extends Scene {
|
|
||||||
ThermionViewer controller;
|
|
||||||
|
|
||||||
SceneImpl(this.controller);
|
|
||||||
|
|
||||||
@override
|
|
||||||
ThermionEntity? selected;
|
|
||||||
|
|
||||||
final _onUpdatedController = StreamController<bool>.broadcast();
|
|
||||||
@override
|
|
||||||
Stream<bool> get onUpdated => _onUpdatedController.stream;
|
|
||||||
|
|
||||||
final _onLoadController = StreamController<ThermionEntity>.broadcast();
|
|
||||||
@override
|
|
||||||
Stream<ThermionEntity> get onLoad => _onLoadController.stream;
|
|
||||||
|
|
||||||
final _onUnloadController = StreamController<ThermionEntity>.broadcast();
|
|
||||||
@override
|
|
||||||
Stream<ThermionEntity> get onUnload => _onUnloadController.stream;
|
|
||||||
|
|
||||||
final _lights = <ThermionEntity>{};
|
|
||||||
final _entities = <ThermionEntity>{};
|
|
||||||
|
|
||||||
void registerLight(ThermionEntity entity) {
|
|
||||||
_lights.add(entity);
|
|
||||||
_onLoadController.sink.add(entity);
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregisterLight(ThermionEntity entity) async {
|
|
||||||
var children = await controller.getChildEntities(entity, true);
|
|
||||||
if (selected == entity || children.contains(selected)) {
|
|
||||||
selected = null;
|
|
||||||
controller.gizmo?.detach();
|
|
||||||
}
|
|
||||||
_lights.remove(entity);
|
|
||||||
_onUnloadController.add(entity);
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregisterEntity(ThermionEntity entity) async {
|
|
||||||
var children = await controller.getChildEntities(entity, true);
|
|
||||||
if (selected == entity || children.contains(selected)) {
|
|
||||||
selected = null;
|
|
||||||
|
|
||||||
controller.gizmo?.detach();
|
|
||||||
}
|
|
||||||
_entities.remove(entity);
|
|
||||||
_onUnloadController.add(entity);
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerEntity(ThermionEntity entity) {
|
|
||||||
_entities.add(entity);
|
|
||||||
_onLoadController.sink.add(entity);
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearLights() {
|
|
||||||
for (final light in _lights) {
|
|
||||||
if (selected == light) {
|
|
||||||
selected = null;
|
|
||||||
controller.gizmo?.detach();
|
|
||||||
}
|
|
||||||
_onUnloadController.add(light);
|
|
||||||
}
|
|
||||||
|
|
||||||
_lights.clear();
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clearEntities() {
|
|
||||||
for (final entity in _entities) {
|
|
||||||
if (selected == entity) {
|
|
||||||
selected = null;
|
|
||||||
controller.gizmo?.detach();
|
|
||||||
}
|
|
||||||
_onUnloadController.add(entity);
|
|
||||||
}
|
|
||||||
_entities.clear();
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Lists all entities currently loaded (not necessarily active in the scene).
|
|
||||||
///
|
|
||||||
Iterable<ThermionEntity> listLights() {
|
|
||||||
return _lights;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Iterable<ThermionEntity> listEntities() {
|
|
||||||
return _entities;
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerSelected(ThermionEntity entity) {
|
|
||||||
selected = entity;
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unregisterSelected() {
|
|
||||||
selected = null;
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
void select(ThermionEntity entity) {
|
|
||||||
selected = entity;
|
|
||||||
controller.gizmo?.attach(entity);
|
|
||||||
_onUpdatedController.add(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future dispose() async {
|
|
||||||
await _onLoadController.close();
|
|
||||||
await _onUnloadController.close();
|
|
||||||
await _onUpdatedController.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,751 +1,6 @@
|
|||||||
import 'dart:math';
|
library thermion_viewer;
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
export 'viewer/thermion_viewer_base.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
export 'viewer/thermion_viewer_stub.dart'
|
||||||
import 'dart:async';
|
if (dart.library.io) 'viewer/ffi/thermion_viewer_ffi.dart'
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
if (dart.library.js_interop) 'viewer/web/thermion_viewer_wasm.dart';
|
||||||
|
|
||||||
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
|
|
||||||
typedef ThermionEntity = int;
|
|
||||||
|
|
||||||
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
|
|
||||||
typedef FilamentPickResult = ({ThermionEntity entity, double x, double y});
|
|
||||||
|
|
||||||
enum LightType {
|
|
||||||
SUN, //!< Directional light that also draws a sun's disk in the sky.
|
|
||||||
DIRECTIONAL, //!< Directional light, emits light in a given direction.
|
|
||||||
POINT, //!< Point light, emits light from a position, in all directions.
|
|
||||||
FOCUSED_SPOT, //!< Physically correct spot light.
|
|
||||||
SPOT,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ShadowType {
|
|
||||||
PCF, //!< percentage-closer filtered shadows (default)
|
|
||||||
VSM, //!< variance shadows
|
|
||||||
DPCF, //!< PCF with contact hardening simulation
|
|
||||||
PCSS, //!< PCF with soft shadows and contact hardening
|
|
||||||
}
|
|
||||||
|
|
||||||
// copied from filament/backened/DriverEnums.h
|
|
||||||
enum PrimitiveType {
|
|
||||||
// don't change the enums values (made to match GL)
|
|
||||||
POINTS, //!< points
|
|
||||||
LINES, //!< lines
|
|
||||||
UNUSED1,
|
|
||||||
LINE_STRIP, //!< line strip
|
|
||||||
TRIANGLES, //!< triangles
|
|
||||||
TRIANGLE_STRIP, //!< triangle strip
|
|
||||||
}
|
|
||||||
|
|
||||||
enum ToneMapper { ACES, FILMIC, LINEAR }
|
|
||||||
|
|
||||||
// see filament Manipulator.h for more details
|
|
||||||
enum ManipulatorMode { ORBIT, MAP, FREE_FLIGHT }
|
|
||||||
|
|
||||||
class TextureDetails {
|
|
||||||
final int textureId;
|
|
||||||
|
|
||||||
// both width and height are in physical, not logical pixels
|
|
||||||
final int width;
|
|
||||||
final int height;
|
|
||||||
|
|
||||||
TextureDetails(
|
|
||||||
{required this.textureId, required this.width, required this.height});
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class ThermionViewer {
|
|
||||||
|
|
||||||
Future<bool> get initialized;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// The result(s) of calling [pick] (see below).
|
|
||||||
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
|
||||||
/// If [pick] is called without an active subscription to this stream, the results will be silently discarded.
|
|
||||||
///
|
|
||||||
Stream<FilamentPickResult> get pickResult;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Whether the controller is currently rendering at [framerate].
|
|
||||||
///
|
|
||||||
bool get rendering;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set to true to continuously render the scene at the framerate specified by [setFrameRate] (60 fps by default).
|
|
||||||
///
|
|
||||||
Future setRendering(bool render);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Render a single frame.
|
|
||||||
///
|
|
||||||
Future render();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
|
|
||||||
///
|
|
||||||
Future setFrameRate(int framerate);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Destroys/disposes the viewer (including the entire scene). You cannot use the viewer after calling this method.
|
|
||||||
///
|
|
||||||
Future dispose();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set the background image to [path] (which should have a file extension .png, .jpg, or .ktx).
|
|
||||||
/// This will be rendered at the maximum depth (i.e. behind all other objects including the skybox).
|
|
||||||
/// If [fillHeight] is false, the image will be rendered at its original size. Note this may cause issues with pixel density so be sure to specify the correct resolution
|
|
||||||
/// If [fillHeight] is true, the image will be stretched/compressed to fit the height of the viewport.
|
|
||||||
///
|
|
||||||
Future setBackgroundImage(String path, {bool fillHeight = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Moves the background image to the relative offset from the origin (bottom-left) specified by [x] and [y].
|
|
||||||
/// If [clamp] is true, the image cannot be positioned outside the bounds of the viewport.
|
|
||||||
///
|
|
||||||
Future setBackgroundImagePosition(double x, double y, {bool clamp = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes the background image.
|
|
||||||
///
|
|
||||||
Future clearBackgroundImage();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox).
|
|
||||||
///
|
|
||||||
Future setBackgroundColor(double r, double g, double b, double alpha);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Load a skybox from [skyboxPath] (which must be a .ktx file)
|
|
||||||
///
|
|
||||||
Future loadSkybox(String skyboxPath);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes the skybox from the scene.
|
|
||||||
///
|
|
||||||
Future removeSkybox();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Loads an image-based light from the specified path at the given intensity.
|
|
||||||
/// Only one IBL can be active at any given time; if an IBL has already been loaded, it will be replaced.
|
|
||||||
///
|
|
||||||
Future loadIbl(String lightingPath, {double intensity = 30000});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Rotates the IBL & skybox.
|
|
||||||
///
|
|
||||||
Future rotateIbl(Matrix3 rotation);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes the image-based light from the scene.
|
|
||||||
///
|
|
||||||
Future removeIbl();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Add a light to the scene.
|
|
||||||
/// See LightManager.h for details
|
|
||||||
/// Note that [sunAngularRadius] is in degrees,
|
|
||||||
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> addLight(
|
|
||||||
LightType type,
|
|
||||||
double colour,
|
|
||||||
double intensity,
|
|
||||||
double posX,
|
|
||||||
double posY,
|
|
||||||
double posZ,
|
|
||||||
double dirX,
|
|
||||||
double dirY,
|
|
||||||
double dirZ,
|
|
||||||
{double falloffRadius = 1.0,
|
|
||||||
double spotLightConeInner = pi / 8,
|
|
||||||
double spotLightConeOuter = pi / 4,
|
|
||||||
double sunAngularRadius = 0.545,
|
|
||||||
double sunHaloSize = 10.0,
|
|
||||||
double sunHaloFallof = 80.0,
|
|
||||||
bool castShadows = true});
|
|
||||||
|
|
||||||
Future removeLight(ThermionEntity light);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Remove all lights (excluding IBL) from the scene.
|
|
||||||
///
|
|
||||||
Future clearLights();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Load the .glb asset at the given path and insert into the scene.
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Create a new instance of [entity].
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> createInstance(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns the number of instances of the asset associated with [entity].
|
|
||||||
///
|
|
||||||
Future<int> getInstanceCount(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns all instances of [entity].
|
|
||||||
///
|
|
||||||
Future<List<ThermionEntity>> getInstances(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Load the .gltf asset at the given path and insert into the scene.
|
|
||||||
/// [relativeResourcePath] is the folder path where the glTF resources are stored;
|
|
||||||
/// this is usually the parent directory of the .gltf file itself.
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
|
||||||
{bool force = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future panStart(double x, double y);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future panUpdate(double x, double y);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future panEnd();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future rotateStart(double x, double y);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future rotateUpdate(double x, double y);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future rotateEnd();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set the weights for all morph targets in [entity] to [weights].
|
|
||||||
/// Note that [weights] must contain values for ALL morph targets, but no exception will be thrown if you don't do so (you'll just get incorrect results).
|
|
||||||
/// If you only want to set one value, set all others to zero (check [getMorphTargetNames] if you need the get a list of all morph targets).
|
|
||||||
/// IMPORTANT - this accepts the actual ThermionEntity with the relevant morph targets (unlike [getMorphTargetNames], which uses the parent entity and the child mesh name).
|
|
||||||
/// Use [getChildEntityByName] if you are setting the weights for a child mesh.
|
|
||||||
///
|
|
||||||
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the names of all morph targets for the child renderable [childEntity] under [entity].
|
|
||||||
///
|
|
||||||
Future<List<String>> getMorphTargetNames(
|
|
||||||
ThermionEntity entity, ThermionEntity childEntity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
|
|
||||||
///
|
|
||||||
Future<List<String>> getBoneNames(ThermionEntity entity, {int skinIndex = 0});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the names of all glTF animations embedded in the specified entity.
|
|
||||||
///
|
|
||||||
Future<List<String>> getAnimationNames(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns the length (in seconds) of the animation at the given index.
|
|
||||||
///
|
|
||||||
Future<double> getAnimationDuration(
|
|
||||||
ThermionEntity entity, int animationIndex);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
|
|
||||||
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
|
|
||||||
/// throwing an exception if any cannot be found.
|
|
||||||
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
|
|
||||||
///
|
|
||||||
Future setMorphAnimationData(
|
|
||||||
ThermionEntity entity, MorphAnimationData animation,
|
|
||||||
{List<String>? targetMeshNames});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Clear all current morph animations for [entity].
|
|
||||||
///
|
|
||||||
Future clearMorphAnimationData(
|
|
||||||
ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Resets all bones in the given entity to their rest pose.
|
|
||||||
/// This should be done before every call to addBoneAnimation.
|
|
||||||
///
|
|
||||||
Future resetBones(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Enqueues and plays the [animation] for the specified bone(s).
|
|
||||||
/// By default, frame data is interpreted as being in *parent* bone space;
|
|
||||||
/// a 45 degree around Y means the bone will rotate 45 degrees around the
|
|
||||||
/// Y axis of the parent bone *in its current orientation*.
|
|
||||||
/// (i.e NOT the parent bone's rest position!).
|
|
||||||
/// Currently, only [Space.ParentBone] and [Space.Model] are supported; if you want
|
|
||||||
/// to transform to another space, you will need to do so manually.
|
|
||||||
///
|
|
||||||
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
|
|
||||||
/// the current active glTF animation ("animation1") and the animation you
|
|
||||||
/// set via this method ("animation2"). The bone orientations will be
|
|
||||||
/// linearly interpolated between animation1 and animation2; at time 0,
|
|
||||||
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
|
|
||||||
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
|
|
||||||
/// This will be applied in reverse after [fadeOutInSecs].
|
|
||||||
///
|
|
||||||
///
|
|
||||||
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
|
||||||
{int skinIndex = 0,
|
|
||||||
double fadeInInSecs = 0.0,
|
|
||||||
double fadeOutInSecs = 0.0,
|
|
||||||
double maxDelta = 1.0});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the entity representing the bone at [boneIndex]/[skinIndex].
|
|
||||||
/// The returned entity is only intended for use with [getWorldTransform].
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
|
|
||||||
{int skinIndex = 0});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the local (relative to parent) transform for [entity].
|
|
||||||
///
|
|
||||||
Future<Matrix4> getLocalTransform(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the world transform for [entity].
|
|
||||||
///
|
|
||||||
Future<Matrix4> getWorldTransform(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the inverse bind (pose) matrix for the bone.
|
|
||||||
/// Note that [parent] must be the ThermionEntity returned by [loadGlb/loadGltf], not any other method ([getChildEntity] etc).
|
|
||||||
/// This is because all joint information is internally stored with the parent entity.
|
|
||||||
///
|
|
||||||
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
|
|
||||||
{int skinIndex = 0});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the transform (relative to its parent) for [entity].
|
|
||||||
///
|
|
||||||
Future setTransform(ThermionEntity entity, Matrix4 transform);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Updates the bone matrices for [entity] (which must be the ThermionEntity
|
|
||||||
/// returned by [loadGlb/loadGltf]).
|
|
||||||
/// Under the hood, this just calls [updateBoneMatrices] on the Animator
|
|
||||||
/// instance of the relevant FilamentInstance (which uses the local
|
|
||||||
/// bone transform and the inverse bind matrix to set the bone matrix).
|
|
||||||
///
|
|
||||||
Future updateBoneMatrices(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Directly set the bone matrix for the bone at the given index.
|
|
||||||
/// Don't call this manually unless you know what you're doing.
|
|
||||||
///
|
|
||||||
Future setBoneTransform(
|
|
||||||
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
|
||||||
{int skinIndex = 0});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes/destroys the specified entity from the scene.
|
|
||||||
/// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete.
|
|
||||||
///
|
|
||||||
Future removeEntity(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes/destroys all renderable entities from the scene (including cameras).
|
|
||||||
/// All [ThermionEntity] handles will no longer be valid after this method is called; ensure you immediately discard all references to all entities once this method is complete.
|
|
||||||
///
|
|
||||||
Future clearEntities();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future zoomBegin();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future zoomUpdate(double x, double y, double z);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
|
||||||
///
|
|
||||||
Future zoomEnd();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
|
||||||
///
|
|
||||||
Future playAnimation(ThermionEntity entity, int index,
|
|
||||||
{bool loop = false,
|
|
||||||
bool reverse = false,
|
|
||||||
bool replaceActive = true,
|
|
||||||
double crossfade = 0.0});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
|
||||||
///
|
|
||||||
Future playAnimationByName(ThermionEntity entity, String name,
|
|
||||||
{bool loop = false,
|
|
||||||
bool reverse = false,
|
|
||||||
bool replaceActive = true,
|
|
||||||
double crossfade = 0.0});
|
|
||||||
|
|
||||||
Future setAnimationFrame(
|
|
||||||
ThermionEntity entity, int index, int animationFrame);
|
|
||||||
|
|
||||||
Future stopAnimation(ThermionEntity entity, int animationIndex);
|
|
||||||
Future stopAnimationByName(ThermionEntity entity, String name);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
|
||||||
///
|
|
||||||
Future setCamera(ThermionEntity entity, String? name);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the current scene camera to the main camera (which is always available and added to every scene by default).
|
|
||||||
///
|
|
||||||
Future setMainCamera();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns the entity associated with the main camera.
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> getMainCamera();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
|
||||||
///
|
|
||||||
Future setCameraFov(double degrees, double width, double height);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the tone mapping (requires postprocessing).
|
|
||||||
///
|
|
||||||
Future setToneMapping(ToneMapper mapper);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the strength of the bloom.
|
|
||||||
///
|
|
||||||
Future setBloom(double bloom);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the focal length of the camera. Default value is 28.0.
|
|
||||||
///
|
|
||||||
Future setCameraFocalLength(double focalLength);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the distance (in world units) to the near/far planes for the active camera. Default values are 0.05/1000.0. See Camera.h for details.
|
|
||||||
///
|
|
||||||
Future setCameraCulling(double near, double far);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the distance (in world units) to the near culling plane for the active camera.
|
|
||||||
///
|
|
||||||
Future<double> getCameraCullingNear();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the distance (in world units) to the far culling plane for the active camera.
|
|
||||||
///
|
|
||||||
Future<double> getCameraCullingFar();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the focus distance for the camera.
|
|
||||||
///
|
|
||||||
Future setCameraFocusDistance(double focusDistance);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera position in world space.
|
|
||||||
///
|
|
||||||
Future<Vector3> getCameraPosition();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera's model matrix.
|
|
||||||
///
|
|
||||||
Future<Matrix4> getCameraModelMatrix();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera's view matrix. See Camera.h for more details.
|
|
||||||
///
|
|
||||||
Future<Matrix4> getCameraViewMatrix();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera's projection matrix. See Camera.h for more details.
|
|
||||||
///
|
|
||||||
Future<Matrix4> getCameraProjectionMatrix();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera's culling projection matrix. See Camera.h for more details.
|
|
||||||
///
|
|
||||||
Future<Matrix4> getCameraCullingProjectionMatrix();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera's culling frustum in world space. Returns a (vector_math) [Frustum] instance where plane0-plane6 define the left, right, bottom, top, far and near planes respectively.
|
|
||||||
/// See Camera.h and (filament) Frustum.h for more details.
|
|
||||||
///
|
|
||||||
Future<Frustum> getCameraFrustum();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set the camera position in world space. Note this is not persistent - any viewport navigation will reset the camera transform.
|
|
||||||
///
|
|
||||||
Future setCameraPosition(double x, double y, double z);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Get the camera rotation matrix.
|
|
||||||
///
|
|
||||||
Future<Matrix3> getCameraRotation();
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Repositions the camera to the last vertex of the bounding box of [entity], looking at the penultimate vertex.
|
|
||||||
///
|
|
||||||
Future moveCameraToAsset(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Enables/disables frustum culling. Currently we don't expose a method for manipulating the camera projection/culling matrices so this is your only option to deal with unwanted near/far clipping.
|
|
||||||
///
|
|
||||||
Future setViewFrustumCulling(bool enabled);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the camera exposure.
|
|
||||||
///
|
|
||||||
Future setCameraExposure(
|
|
||||||
double aperture, double shutterSpeed, double sensitivity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Rotate the camera by [rads] around the given axis. Note this is not persistent - any viewport navigation will reset the camera transform.
|
|
||||||
///
|
|
||||||
Future setCameraRotation(Quaternion quaternion);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the camera model matrix.
|
|
||||||
///
|
|
||||||
Future setCameraModelMatrix(List<double> matrix);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the `baseColorFactor` property for the material at index [materialIndex] in [entity] under node [meshName] to [color].
|
|
||||||
///
|
|
||||||
Future setMaterialColor(ThermionEntity entity, String meshName,
|
|
||||||
int materialIndex, double r, double g, double b, double a);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Scale [entity] to fit within the unit cube.
|
|
||||||
///
|
|
||||||
Future transformToUnitCube(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Directly sets the world space position for [entity] to the given coordinates, skipping all collision detection.
|
|
||||||
///
|
|
||||||
Future setPosition(ThermionEntity entity, double x, double y, double z);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Directly sets the scale for [entity], skipping all collision detection.
|
|
||||||
///
|
|
||||||
Future setScale(ThermionEntity entity, double scale);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Directly sets the rotation for [entity] to [rads] around the axis {x,y,z}, skipping all collision detection.
|
|
||||||
///
|
|
||||||
Future setRotation(
|
|
||||||
ThermionEntity entity, double rads, double x, double y, double z);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Queues an update to the worldspace position for [entity] to {x,y,z}.
|
|
||||||
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
|
||||||
///
|
|
||||||
Future queuePositionUpdate(
|
|
||||||
ThermionEntity entity, double x, double y, double z,
|
|
||||||
{bool relative = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Queues an update to the worldspace rotation for [entity].
|
|
||||||
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
|
||||||
///
|
|
||||||
Future queueRotationUpdate(
|
|
||||||
ThermionEntity entity, double rads, double x, double y, double z,
|
|
||||||
{bool relative = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Same as [queueRotationUpdate].
|
|
||||||
///
|
|
||||||
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
|
|
||||||
{bool relative = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Enable/disable postprocessing (disabled by default).
|
|
||||||
///
|
|
||||||
Future setPostProcessing(bool enabled);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Enable/disable shadows (disabled by default).
|
|
||||||
///
|
|
||||||
Future setShadowsEnabled(bool enabled);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set shadow type.
|
|
||||||
///
|
|
||||||
Future setShadowType(ShadowType shadowType);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set soft shadow options (ShadowType DPCF and PCSS)
|
|
||||||
///
|
|
||||||
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Set antialiasing options.
|
|
||||||
///
|
|
||||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the rotation for [entity] to the specified quaternion.
|
|
||||||
///
|
|
||||||
Future setRotationQuat(ThermionEntity entity, Quaternion rotation);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
|
|
||||||
///
|
|
||||||
Future reveal(ThermionEntity entity, String? meshName);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity].
|
|
||||||
/// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering.
|
|
||||||
///
|
|
||||||
Future hide(ThermionEntity entity, String? meshName);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Used to select the entity in the scene at the given viewport coordinates.
|
|
||||||
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
|
||||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
|
|
||||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
|
||||||
///
|
|
||||||
void pick(int x, int y);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
|
|
||||||
///
|
|
||||||
String? getNameForEntity(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the options for manipulating the camera via the viewport.
|
|
||||||
/// ManipulatorMode.FREE_FLIGHT and ManipulatorMode.MAP are currently unsupported and will throw an exception.
|
|
||||||
///
|
|
||||||
Future setCameraManipulatorOptions(
|
|
||||||
{ManipulatorMode mode = ManipulatorMode.ORBIT,
|
|
||||||
double orbitSpeedX = 0.01,
|
|
||||||
double orbitSpeedY = 0.01,
|
|
||||||
double zoomSpeed = 0.01});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Returns all child entities under [parent].
|
|
||||||
///
|
|
||||||
Future<List<ThermionEntity>> getChildEntities(
|
|
||||||
ThermionEntity parent, bool renderableOnly);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Finds the child entity named [childName] associated with the given parent.
|
|
||||||
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
|
|
||||||
///
|
|
||||||
Future<ThermionEntity> getChildEntity(
|
|
||||||
ThermionEntity parent, String childName);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// List the name of all child entities under the given entity.
|
|
||||||
///
|
|
||||||
Future<List<String>> getChildEntityNames(ThermionEntity entity,
|
|
||||||
{bool renderableOnly = true});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// If [recording] is set to true, each frame the framebuffer/texture will be written to /tmp/output_*.png.
|
|
||||||
/// This will impact performance; handle with care.
|
|
||||||
///
|
|
||||||
Future setRecording(bool recording);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the output directory where recorded PNGs will be placed.
|
|
||||||
///
|
|
||||||
Future setRecordingOutputDirectory(String outputDirectory);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// An [entity] will only be animatable after an animation component is attached.
|
|
||||||
/// Any calls to [playAnimation]/[setBoneAnimation]/[setMorphAnimation] will have no visual effect until [addAnimationComponent] has been called on the instance.
|
|
||||||
///
|
|
||||||
Future addAnimationComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes an animation component from [entity].
|
|
||||||
///
|
|
||||||
Future removeAnimationComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Makes [entity] collidable.
|
|
||||||
/// This allows you to call [testCollisions] with any other entity ("entity B") to see if [entity] has collided with entity B. The callback will be invoked if so.
|
|
||||||
/// Alternatively, if [affectsTransform] is true and this entity collides with another entity, any queued position updates to the latter entity will be ignored.
|
|
||||||
///
|
|
||||||
Future addCollisionComponent(ThermionEntity entity,
|
|
||||||
{void Function(int entityId1, int entityId2)? callback,
|
|
||||||
bool affectsTransform = false});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Removes the collision component from [entity], meaning this will no longer be tested when [testCollisions] or [queuePositionUpdate] is called with another entity.
|
|
||||||
///
|
|
||||||
Future removeCollisionComponent(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Creates a (renderable) entity with the specified geometry and adds to the scene.
|
|
||||||
///
|
|
||||||
Future createGeometry(List<double> vertices, List<int> indices,
|
|
||||||
{String? materialPath,
|
|
||||||
PrimitiveType primitiveType = PrimitiveType.TRIANGLES});
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Gets the parent transform of [child].
|
|
||||||
///
|
|
||||||
Future<ThermionEntity?> getParent(ThermionEntity child);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the parent transform of [child] to [parent].
|
|
||||||
///
|
|
||||||
Future setParent(ThermionEntity child, ThermionEntity parent);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Test all collidable entities against this entity to see if any have collided.
|
|
||||||
/// This method returns void; the relevant callback passed to [addCollisionComponent] will be fired if a collision is detected.
|
|
||||||
///
|
|
||||||
Future testCollisions(ThermionEntity entity);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
|
|
||||||
///
|
|
||||||
Future setPriority(ThermionEntity entityId, int priority);
|
|
||||||
|
|
||||||
///
|
|
||||||
/// The Scene holds all loaded entities/lights.
|
|
||||||
///
|
|
||||||
Scene get scene;
|
|
||||||
|
|
||||||
///
|
|
||||||
///
|
|
||||||
///
|
|
||||||
AbstractGizmo? get gizmo;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// Register a callback to be invoked when this viewer is disposed.
|
|
||||||
///
|
|
||||||
void onDispose(Future Function() callback);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class AbstractGizmo {
|
|
||||||
bool get isActive;
|
|
||||||
|
|
||||||
void translate(double transX, double transY);
|
|
||||||
|
|
||||||
void reset();
|
|
||||||
|
|
||||||
void attach(ThermionEntity entity);
|
|
||||||
|
|
||||||
void detach();
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'dart:ffi';
|
import 'dart:ffi';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import '../compatibility/compatibility.dart';
|
|
||||||
|
import 'package:ffi/ffi.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/ffi/thermion_dart.g.dart';
|
||||||
|
|
||||||
class DartResourceLoader {
|
class DartResourceLoader {
|
||||||
static final _assets = <int, Pointer>{};
|
static final _assets = <int, Pointer>{};
|
||||||
|
|||||||
334
thermion_dart/lib/thermion_dart/utils/geometry.dart
Normal file
334
thermion_dart/lib/thermion_dart/utils/geometry.dart
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/shared_types/geometry.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
|
||||||
|
|
||||||
|
class GeometryHelper {
|
||||||
|
static Geometry sphere({bool normals = true, bool uvs = true}) {
|
||||||
|
int latitudeBands = 20;
|
||||||
|
int longitudeBands = 20;
|
||||||
|
|
||||||
|
List<double> verticesList = [];
|
||||||
|
List<double> normalsList = [];
|
||||||
|
List<double> uvsList = [];
|
||||||
|
List<int> indices = [];
|
||||||
|
|
||||||
|
for (int latNumber = 0; latNumber <= latitudeBands; latNumber++) {
|
||||||
|
double theta = latNumber * pi / latitudeBands;
|
||||||
|
double sinTheta = sin(theta);
|
||||||
|
double cosTheta = cos(theta);
|
||||||
|
|
||||||
|
for (int longNumber = 0; longNumber <= longitudeBands; longNumber++) {
|
||||||
|
double phi = longNumber * 2 * pi / longitudeBands;
|
||||||
|
double sinPhi = sin(phi);
|
||||||
|
double cosPhi = cos(phi);
|
||||||
|
|
||||||
|
double x = cosPhi * sinTheta;
|
||||||
|
double y = cosTheta;
|
||||||
|
double z = sinPhi * sinTheta;
|
||||||
|
|
||||||
|
verticesList.addAll([x, y, z]);
|
||||||
|
normalsList.addAll([x, y, z]);
|
||||||
|
|
||||||
|
uvsList.addAll([longNumber / longitudeBands, latNumber / latitudeBands]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int latNumber = 0; latNumber < latitudeBands; latNumber++) {
|
||||||
|
for (int longNumber = 0; longNumber < longitudeBands; longNumber++) {
|
||||||
|
int first = (latNumber * (longitudeBands + 1)) + longNumber;
|
||||||
|
int second = first + longitudeBands + 1;
|
||||||
|
|
||||||
|
indices.addAll([first, second, first + 1, second, second + 1, first + 1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Float32List vertices = Float32List.fromList(verticesList);
|
||||||
|
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
|
||||||
|
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
|
||||||
|
|
||||||
|
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Geometry cube({bool normals = true, bool uvs = true}) {
|
||||||
|
final vertices = Float32List.fromList([
|
||||||
|
// Front face
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
-1, -1, -1,
|
||||||
|
-1, 1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
1, -1, -1,
|
||||||
|
|
||||||
|
// Top face
|
||||||
|
-1, 1, -1,
|
||||||
|
-1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, 1, -1,
|
||||||
|
|
||||||
|
// Bottom face
|
||||||
|
-1, -1, -1,
|
||||||
|
1, -1, -1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, -1, 1,
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
1, -1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
1, 1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
-1, -1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
]);
|
||||||
|
|
||||||
|
final _normals = normals ? Float32List.fromList([
|
||||||
|
// Front face
|
||||||
|
0, 0, 1,
|
||||||
|
0, 0, 1,
|
||||||
|
0, 0, 1,
|
||||||
|
0, 0, 1,
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
0, 0, -1,
|
||||||
|
0, 0, -1,
|
||||||
|
0, 0, -1,
|
||||||
|
0, 0, -1,
|
||||||
|
|
||||||
|
// Top face
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
|
||||||
|
// Bottom face
|
||||||
|
0, -1, 0,
|
||||||
|
0, -1, 0,
|
||||||
|
0, -1, 0,
|
||||||
|
0, -1, 0,
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
1, 0, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
1, 0, 0,
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
-1, 0, 0,
|
||||||
|
-1, 0, 0,
|
||||||
|
-1, 0, 0,
|
||||||
|
-1, 0, 0,
|
||||||
|
]) : null;
|
||||||
|
|
||||||
|
final _uvs = uvs ? Float32List.fromList([
|
||||||
|
// Front face
|
||||||
|
1/3, 1/3,
|
||||||
|
2/3, 1/3,
|
||||||
|
2/3, 2/3,
|
||||||
|
1/3, 2/3,
|
||||||
|
|
||||||
|
// Back face
|
||||||
|
2/3, 2/3,
|
||||||
|
2/3, 1,
|
||||||
|
1, 1,
|
||||||
|
1, 2/3,
|
||||||
|
|
||||||
|
// Top face
|
||||||
|
1/3, 0,
|
||||||
|
1/3, 1/3,
|
||||||
|
2/3, 1/3,
|
||||||
|
2/3, 0,
|
||||||
|
|
||||||
|
// Bottom face
|
||||||
|
1/3, 2/3,
|
||||||
|
2/3, 2/3,
|
||||||
|
2/3, 1,
|
||||||
|
1/3, 1,
|
||||||
|
|
||||||
|
// Right face
|
||||||
|
2/3, 1/3,
|
||||||
|
2/3, 2/3,
|
||||||
|
1, 2/3,
|
||||||
|
1, 1/3,
|
||||||
|
|
||||||
|
// Left face
|
||||||
|
0, 1/3,
|
||||||
|
1/3, 1/3,
|
||||||
|
1/3, 2/3,
|
||||||
|
0, 2/3,
|
||||||
|
]) : null;
|
||||||
|
|
||||||
|
final indices = [
|
||||||
|
// Front face
|
||||||
|
0, 1, 2, 0, 2, 3,
|
||||||
|
// Back face
|
||||||
|
4, 5, 6, 4, 6, 7,
|
||||||
|
// Top face
|
||||||
|
8, 9, 10, 8, 10, 11,
|
||||||
|
// Bottom face
|
||||||
|
12, 13, 14, 12, 14, 15,
|
||||||
|
// Right face
|
||||||
|
16, 17, 18, 16, 18, 19,
|
||||||
|
// Left face
|
||||||
|
20, 21, 22, 20, 22, 23
|
||||||
|
];
|
||||||
|
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Geometry cylinder({double radius = 1.0, double length = 1.0, bool normals = true, bool uvs = true }) {
|
||||||
|
int segments = 32;
|
||||||
|
List<double> verticesList = [];
|
||||||
|
List<double> normalsList = [];
|
||||||
|
List<double> uvsList = [];
|
||||||
|
List<int> indices = [];
|
||||||
|
|
||||||
|
// Create vertices, normals, and UVs
|
||||||
|
for (int i = 0; i <= segments; i++) {
|
||||||
|
double theta = i * 2 * pi / segments;
|
||||||
|
double x = radius * cos(theta);
|
||||||
|
double z = radius * sin(theta);
|
||||||
|
|
||||||
|
// Top circle
|
||||||
|
verticesList.addAll([x, length / 2, z]);
|
||||||
|
normalsList.addAll([x / radius, 0, z / radius]);
|
||||||
|
uvsList.addAll([i / segments, 1]);
|
||||||
|
|
||||||
|
// Bottom circle
|
||||||
|
verticesList.addAll([x, -length / 2, z]);
|
||||||
|
normalsList.addAll([x / radius, 0, z / radius]);
|
||||||
|
uvsList.addAll([i / segments, 0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create indices
|
||||||
|
for (int i = 0; i < segments; i++) {
|
||||||
|
int topFirst = i * 2;
|
||||||
|
int topSecond = (i + 1) * 2;
|
||||||
|
int bottomFirst = topFirst + 1;
|
||||||
|
int bottomSecond = topSecond + 1;
|
||||||
|
|
||||||
|
// Top face (counter-clockwise)
|
||||||
|
indices.addAll([segments * 2, topSecond, topFirst]);
|
||||||
|
// Bottom face (counter-clockwise when viewed from below)
|
||||||
|
indices.addAll([segments * 2 + 1, bottomFirst, bottomSecond]);
|
||||||
|
// Side faces (counter-clockwise)
|
||||||
|
indices.addAll([topFirst, bottomFirst, topSecond]);
|
||||||
|
indices.addAll([bottomFirst, bottomSecond, topSecond]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add center vertices, normals, and UVs for top and bottom faces
|
||||||
|
verticesList.addAll([0, length / 2, 0]); // Top center
|
||||||
|
normalsList.addAll([0, 1, 0]);
|
||||||
|
uvsList.addAll([0.5, 0.5]); // Center of top face
|
||||||
|
|
||||||
|
verticesList.addAll([0, -length / 2, 0]); // Bottom center
|
||||||
|
normalsList.addAll([0, -1, 0]);
|
||||||
|
uvsList.addAll([0.5, 0.5]); // Center of bottom face
|
||||||
|
|
||||||
|
// Add top and bottom face normals and UVs
|
||||||
|
for (int i = 0; i <= segments; i++) {
|
||||||
|
normalsList.addAll([0, 1, 0]); // Top face normal
|
||||||
|
normalsList.addAll([0, -1, 0]); // Bottom face normal
|
||||||
|
|
||||||
|
double u = 0.5 + 0.5 * cos(i * 2 * pi / segments);
|
||||||
|
double v = 0.5 + 0.5 * sin(i * 2 * pi / segments);
|
||||||
|
uvsList.addAll([u, v]); // Top face UV
|
||||||
|
uvsList.addAll([u, v]); // Bottom face UV
|
||||||
|
}
|
||||||
|
|
||||||
|
Float32List vertices = Float32List.fromList(verticesList);
|
||||||
|
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
|
||||||
|
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
|
||||||
|
|
||||||
|
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Geometry conic({double radius = 1.0, double length = 1.0, bool normals = true, bool uvs = true}) {
|
||||||
|
int segments = 32;
|
||||||
|
List<double> verticesList = [];
|
||||||
|
List<double> normalsList = [];
|
||||||
|
List<double> uvsList = [];
|
||||||
|
List<int> indices = [];
|
||||||
|
|
||||||
|
// Create vertices, normals, and UVs
|
||||||
|
for (int i = 0; i <= segments; i++) {
|
||||||
|
double theta = i * 2 * pi / segments;
|
||||||
|
double x = radius * cos(theta);
|
||||||
|
double z = radius * sin(theta);
|
||||||
|
|
||||||
|
// Base circle
|
||||||
|
verticesList.addAll([x, 0, z]);
|
||||||
|
|
||||||
|
// Calculate normal for the side
|
||||||
|
double nx = x / sqrt(x * x + length * length);
|
||||||
|
double nz = z / sqrt(z * z + length * length);
|
||||||
|
double ny = radius / sqrt(radius * radius + length * length);
|
||||||
|
normalsList.addAll([nx, ny, nz]);
|
||||||
|
|
||||||
|
// UV coordinates
|
||||||
|
uvsList.addAll([i / segments, 0]);
|
||||||
|
}
|
||||||
|
// Apex
|
||||||
|
verticesList.addAll([0, length, 0]);
|
||||||
|
normalsList.addAll([0, 1, 0]); // Normal at apex points straight up
|
||||||
|
uvsList.addAll([0.5, 1]); // UV for apex
|
||||||
|
|
||||||
|
// Create indices
|
||||||
|
for (int i = 0; i < segments; i++) {
|
||||||
|
// Base face (fixed to counterclockwise)
|
||||||
|
indices.addAll([segments + 1, i + 1, i]);
|
||||||
|
// Side faces (already correct)
|
||||||
|
indices.addAll([i, segments, i + 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add base face normals and UVs
|
||||||
|
for (int i = 0; i <= segments; i++) {
|
||||||
|
normalsList.addAll([0, -1, 0]); // Base face normal
|
||||||
|
double u = 0.5 + 0.5 * cos(i * 2 * pi / segments);
|
||||||
|
double v = 0.5 + 0.5 * sin(i * 2 * pi / segments);
|
||||||
|
uvsList.addAll([u, v]); // Base face UV
|
||||||
|
}
|
||||||
|
|
||||||
|
Float32List vertices = Float32List.fromList(verticesList);
|
||||||
|
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
|
||||||
|
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
|
||||||
|
|
||||||
|
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Geometry plane({double width = 1.0, double height = 1.0, bool normals = true, bool uvs = true}) {
|
||||||
|
Float32List vertices = Float32List.fromList([
|
||||||
|
-width / 2, 0, -height / 2,
|
||||||
|
width / 2, 0, -height / 2,
|
||||||
|
width / 2, 0, height / 2,
|
||||||
|
-width / 2, 0, height / 2,
|
||||||
|
]);
|
||||||
|
|
||||||
|
Float32List? _normals = normals ? Float32List.fromList([
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
0, 1, 0,
|
||||||
|
]) : null;
|
||||||
|
|
||||||
|
Float32List? _uvs = uvs ? Float32List.fromList([
|
||||||
|
0, 0,
|
||||||
|
1, 0,
|
||||||
|
1, 1,
|
||||||
|
0, 1,
|
||||||
|
]) : null;
|
||||||
|
|
||||||
|
List<int> indices = [
|
||||||
|
0, 2, 1,
|
||||||
|
0, 3, 2,
|
||||||
|
];
|
||||||
|
|
||||||
|
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import 'package:vector_math/vector_math_64.dart' as v;
|
|
||||||
|
|
||||||
class LightOptions {
|
|
||||||
String? iblPath;
|
|
||||||
double iblIntensity;
|
|
||||||
int directionalType;
|
|
||||||
double directionalColor;
|
|
||||||
double directionalIntensity;
|
|
||||||
bool directionalCastShadows;
|
|
||||||
late v.Vector3 directionalPosition;
|
|
||||||
late v.Vector3 directionalDirection;
|
|
||||||
|
|
||||||
LightOptions(
|
|
||||||
{required this.iblPath,
|
|
||||||
required this.iblIntensity,
|
|
||||||
required this.directionalType,
|
|
||||||
required this.directionalColor,
|
|
||||||
required this.directionalIntensity,
|
|
||||||
required this.directionalCastShadows,
|
|
||||||
v.Vector3? directionalDirection,
|
|
||||||
v.Vector3? directionalPosition}) {
|
|
||||||
this.directionalDirection = directionalDirection == null
|
|
||||||
? v.Vector3(0, -1, 0)
|
|
||||||
: directionalDirection;
|
|
||||||
this.directionalPosition = directionalPosition == null
|
|
||||||
? v.Vector3(0, 100, 0)
|
|
||||||
: directionalPosition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
38
thermion_dart/lib/thermion_dart/utils/matrix.dart
Normal file
38
thermion_dart/lib/thermion_dart/utils/matrix.dart
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
// Helper function to convert double4x4 to Matrix4
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/ffi/thermion_dart.g.dart';
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
Matrix4 double4x4ToMatrix4(double4x4 mat) {
|
||||||
|
return Matrix4.fromList([
|
||||||
|
mat.col1[0],
|
||||||
|
mat.col1[1],
|
||||||
|
mat.col1[2],
|
||||||
|
mat.col1[3],
|
||||||
|
mat.col2[0],
|
||||||
|
mat.col2[1],
|
||||||
|
mat.col2[2],
|
||||||
|
mat.col2[3],
|
||||||
|
mat.col3[0],
|
||||||
|
mat.col3[1],
|
||||||
|
mat.col3[2],
|
||||||
|
mat.col3[3],
|
||||||
|
mat.col4[0],
|
||||||
|
mat.col4[1],
|
||||||
|
mat.col4[2],
|
||||||
|
mat.col4[3],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
double4x4 matrix4ToDouble4x4(Matrix4 mat) {
|
||||||
|
final out = Struct.create<double4x4>();
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
out.col1[i] = mat.storage[i];
|
||||||
|
out.col2[i] = mat.storage[i + 4];
|
||||||
|
out.col3[i] = mat.storage[i + 8];
|
||||||
|
out.col4[i] = mat.storage[i + 12];
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import 'dart:ffi';
|
|
||||||
|
|
||||||
import 'package:ffi/ffi.dart';
|
|
||||||
|
|
||||||
final allocator = calloc;
|
|
||||||
|
|
||||||
void using(Pointer ptr, Future Function(Pointer ptr) function) async {
|
|
||||||
await function.call(ptr);
|
|
||||||
allocator.free(ptr);
|
|
||||||
}
|
|
||||||
86
thermion_dart/lib/thermion_dart/viewer/events.dart
Normal file
86
thermion_dart/lib/thermion_dart/viewer/events.dart
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import 'package:thermion_dart/thermion_dart/viewer/shared_types/entities.dart';
|
||||||
|
import 'shared_types/shared_types.dart';
|
||||||
|
|
||||||
|
///
|
||||||
|
/// To ensure we can easily store/recreate a particular, [ThermionViewer] will raise an event whenever an
|
||||||
|
/// entity is added/removed.
|
||||||
|
///
|
||||||
|
enum EventType { EntityAdded, EntityRemoved, EntityHidden, EntityRevealed, ClearLights }
|
||||||
|
|
||||||
|
///
|
||||||
|
/// An "entity added" event must provide sufficient detail to enable that asset to be reloaded in future.
|
||||||
|
/// This requires a bit more legwork because entities may be lights (direct/indirect), geometry or gltf.
|
||||||
|
///
|
||||||
|
enum EntityType { Geometry, Gltf, DirectLight, IBL }
|
||||||
|
|
||||||
|
class SceneUpdateEvent {
|
||||||
|
late final ThermionEntity? entity;
|
||||||
|
late final EventType eventType;
|
||||||
|
|
||||||
|
EntityType get addedEntityType {
|
||||||
|
if (_directLight != null) {
|
||||||
|
return EntityType.DirectLight;
|
||||||
|
} else if (_ibl != null) {
|
||||||
|
return EntityType.IBL;
|
||||||
|
} else if (_gltf != null) {
|
||||||
|
return EntityType.Gltf;
|
||||||
|
} else if (_geometry != null) {
|
||||||
|
return EntityType.Geometry;
|
||||||
|
} else {
|
||||||
|
throw Exception("Unknown entity type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectLight? _directLight;
|
||||||
|
IBL? _ibl;
|
||||||
|
GLTF? _gltf;
|
||||||
|
Geometry? _geometry;
|
||||||
|
|
||||||
|
SceneUpdateEvent.remove(this.entity) {
|
||||||
|
this.eventType = EventType.EntityRemoved;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.reveal(this.entity) {
|
||||||
|
this.eventType = EventType.EntityRevealed;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.hide(this.entity) {
|
||||||
|
this.eventType = EventType.EntityHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.addDirectLight(this.entity, this._directLight) {
|
||||||
|
this.eventType = EventType.EntityAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.addIbl(this.entity, this._ibl) {
|
||||||
|
this.eventType = EventType.EntityAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.addGltf(this.entity, this._gltf) {
|
||||||
|
this.eventType = EventType.EntityAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.addGeometry(this.entity, this._geometry) {
|
||||||
|
this.eventType = EventType.EntityAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneUpdateEvent.clearLights() {
|
||||||
|
this.eventType = EventType.ClearLights;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectLight getDirectLight() {
|
||||||
|
return _directLight!;
|
||||||
|
}
|
||||||
|
|
||||||
|
IBL getAsIBL() {
|
||||||
|
return _ibl!;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLTF getAsGLTF() {
|
||||||
|
return _gltf!;
|
||||||
|
}
|
||||||
|
|
||||||
|
Geometry getAsGeometry() {
|
||||||
|
return _geometry!;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,11 @@ export 'thermion_dart.g.dart';
|
|||||||
|
|
||||||
final allocator = calloc;
|
final allocator = calloc;
|
||||||
|
|
||||||
|
void using(Pointer ptr, Future Function(Pointer ptr) function) async {
|
||||||
|
await function.call(ptr);
|
||||||
|
allocator.free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> withVoidCallback(
|
Future<void> withVoidCallback(
|
||||||
Function(Pointer<NativeFunction<Void Function()>>) func) async {
|
Function(Pointer<NativeFunction<Void Function()>>) func) async {
|
||||||
final completer = Completer();
|
final completer = Completer();
|
||||||
@@ -21,16 +26,16 @@ Future<void> withVoidCallback(
|
|||||||
nativeCallable.close();
|
nativeCallable.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<int> withVoidPointerCallback(
|
Future<int> withPointerCallback<T extends NativeType>(
|
||||||
Function(Pointer<NativeFunction<Void Function(Pointer<Void>)>>)
|
Function(Pointer<NativeFunction<Void Function(Pointer<T>)>>)
|
||||||
func) async {
|
func) async {
|
||||||
final completer = Completer<Pointer<Void>>();
|
final completer = Completer<Pointer<T>>();
|
||||||
// ignore: prefer_function_declarations_over_variables
|
// ignore: prefer_function_declarations_over_variables
|
||||||
void Function(Pointer<Void>) callback = (Pointer<Void> ptr) {
|
void Function(Pointer<NativeType>) callback = (Pointer<NativeType> ptr) {
|
||||||
completer.complete(ptr);
|
completer.complete(ptr.cast<T>());
|
||||||
};
|
};
|
||||||
final nativeCallable =
|
final nativeCallable =
|
||||||
NativeCallable<Void Function(Pointer<Void>)>.listener(callback);
|
NativeCallable<Void Function(Pointer<NativeType>)>.listener(callback);
|
||||||
func.call(nativeCallable.nativeFunction);
|
func.call(nativeCallable.nativeFunction);
|
||||||
var ptr = await completer.future;
|
var ptr = await completer.future;
|
||||||
nativeCallable.close();
|
nativeCallable.close();
|
||||||
@@ -82,4 +87,3 @@ Future<String> withCharPtrCallback(
|
|||||||
return completer.future;
|
return completer.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Compatibility {}
|
|
||||||
22
thermion_dart/lib/thermion_dart/viewer/ffi/camera_ffi.dart
Normal file
22
thermion_dart/lib/thermion_dart/viewer/ffi/camera_ffi.dart
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import 'dart:ffi';
|
||||||
|
|
||||||
|
import 'package:thermion_dart/thermion_dart/utils/matrix.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/ffi/thermion_dart.g.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
|
class ThermionFFICamera extends Camera {
|
||||||
|
final Pointer<TCamera> pointer;
|
||||||
|
|
||||||
|
ThermionFFICamera(this.pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setProjectionMatrixWithCulling(Matrix4 projectionMatrix,
|
||||||
|
double near, double far) async {
|
||||||
|
Camera_setCustomProjectionWithCulling(
|
||||||
|
pointer,
|
||||||
|
matrix4ToDouble4x4(projectionMatrix),
|
||||||
|
near,
|
||||||
|
far);
|
||||||
|
}
|
||||||
|
}
|
||||||
2127
thermion_dart/lib/thermion_dart/viewer/ffi/thermion_dart.g.dart
Normal file
2127
thermion_dart/lib/thermion_dart/viewer/ffi/thermion_dart.g.dart
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
|||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
|
||||||
|
abstract class Camera {
|
||||||
|
|
||||||
|
Future setProjectionMatrixWithCulling(Matrix4 projectionMatrix, double near, double far);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
library;
|
||||||
|
|
||||||
|
export 'geometry.dart';
|
||||||
|
export 'gltf.dart';
|
||||||
|
|
||||||
|
export 'light_options.dart';
|
||||||
|
|
||||||
|
// a handle that can be safely passed back to the rendering layer to manipulate an Entity
|
||||||
|
typedef ThermionEntity = int;
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
|
||||||
|
|
||||||
|
class Geometry {
|
||||||
|
final Float32List vertices;
|
||||||
|
final Uint16List indices;
|
||||||
|
final Float32List normals;
|
||||||
|
final Float32List uvs;
|
||||||
|
final PrimitiveType primitiveType;
|
||||||
|
|
||||||
|
Geometry(
|
||||||
|
this.vertices,
|
||||||
|
List<int> indices, {
|
||||||
|
Float32List? normals,
|
||||||
|
Float32List? uvs,
|
||||||
|
this.primitiveType = PrimitiveType.TRIANGLES,
|
||||||
|
}) : indices = Uint16List.fromList(indices),
|
||||||
|
normals = normals ?? Float32List(0),
|
||||||
|
uvs = uvs ?? Float32List(0) {
|
||||||
|
assert(this.uvs.length == 0 || this.uvs.length == (vertices.length ~/ 3) * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void scale(double factor) {
|
||||||
|
for (int i = 0; i < vertices.length; i++) {
|
||||||
|
vertices[i] = vertices[i] * factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get hasNormals => normals.isNotEmpty;
|
||||||
|
bool get hasUVs => uvs.isNotEmpty;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
class GLTF {
|
||||||
|
final String uri;
|
||||||
|
final int numInstances;
|
||||||
|
|
||||||
|
GLTF(this.uri, this.numInstances);
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
enum LightType {
|
||||||
|
SUN, //!< Directional light that also draws a sun's disk in the sky.
|
||||||
|
DIRECTIONAL, //!< Directional light, emits light in a given direction.
|
||||||
|
POINT, //!< Point light, emits light from a position, in all directions.
|
||||||
|
FOCUSED_SPOT, //!< Physically correct spot light.
|
||||||
|
SPOT,
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
import 'package:vector_math/vector_math_64.dart' as v;
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
import 'light.dart';
|
||||||
|
|
||||||
|
class IBL {
|
||||||
|
String? iblPath;
|
||||||
|
final double iblIntensity;
|
||||||
|
|
||||||
|
IBL(this.iblIntensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DirectLight {
|
||||||
|
final LightType type;
|
||||||
|
final double color;
|
||||||
|
final double intensity;
|
||||||
|
final bool castShadows;
|
||||||
|
late final v.Vector3 position;
|
||||||
|
late final v.Vector3 direction;
|
||||||
|
final double falloffRadius;
|
||||||
|
final double spotLightConeInner;
|
||||||
|
final double spotLightConeOuter;
|
||||||
|
final double sunAngularRadius;
|
||||||
|
final double sunHaloSize;
|
||||||
|
final double sunHaloFallof;
|
||||||
|
|
||||||
|
DirectLight({
|
||||||
|
required this.type,
|
||||||
|
required this.color,
|
||||||
|
required this.intensity,
|
||||||
|
this.castShadows = false,
|
||||||
|
required this.direction,
|
||||||
|
required this.position,
|
||||||
|
this.falloffRadius = 1.0,
|
||||||
|
this.spotLightConeInner = pi / 8,
|
||||||
|
this.spotLightConeOuter = pi / 4,
|
||||||
|
this.sunAngularRadius = 0.545,
|
||||||
|
this.sunHaloSize = 10.0,
|
||||||
|
this.sunHaloFallof = 80.0,
|
||||||
|
});
|
||||||
|
|
||||||
|
DirectLight.point({
|
||||||
|
double color = 6500,
|
||||||
|
double intensity = 100000,
|
||||||
|
bool castShadows = false,
|
||||||
|
Vector3? position,
|
||||||
|
double falloffRadius = 1.0,
|
||||||
|
}) : this(
|
||||||
|
type: LightType.POINT,
|
||||||
|
color: color,
|
||||||
|
intensity: intensity,
|
||||||
|
castShadows: castShadows,
|
||||||
|
position: position ?? Vector3(0, 1, 0),
|
||||||
|
direction: Vector3.zero(),
|
||||||
|
falloffRadius: falloffRadius,
|
||||||
|
);
|
||||||
|
|
||||||
|
DirectLight.sun({
|
||||||
|
double color = 6500,
|
||||||
|
double intensity = 100000,
|
||||||
|
bool castShadows = true,
|
||||||
|
Vector3? direction,
|
||||||
|
double sunAngularRadius = 0.545,
|
||||||
|
double sunHaloSize = 10.0,
|
||||||
|
double sunHaloFalloff = 80.0,
|
||||||
|
}) : this(
|
||||||
|
type: LightType.DIRECTIONAL,
|
||||||
|
color: color,
|
||||||
|
intensity: intensity,
|
||||||
|
castShadows: castShadows,
|
||||||
|
position: Vector3(0, 0, 0),
|
||||||
|
direction: direction ?? Vector3(0, -1, 0),
|
||||||
|
sunAngularRadius: sunAngularRadius,
|
||||||
|
sunHaloSize: sunHaloSize,
|
||||||
|
sunHaloFallof: sunHaloFalloff,
|
||||||
|
);
|
||||||
|
|
||||||
|
DirectLight.spot({
|
||||||
|
double color = 6500,
|
||||||
|
double intensity = 100000,
|
||||||
|
bool castShadows = true,
|
||||||
|
Vector3? position,
|
||||||
|
Vector3? direction,
|
||||||
|
double falloffRadius = 1.0,
|
||||||
|
double spotLightConeInner = pi / 8,
|
||||||
|
double spotLightConeOuter = pi / 4,
|
||||||
|
}) : this(
|
||||||
|
type: LightType.SPOT,
|
||||||
|
color: color,
|
||||||
|
intensity: intensity,
|
||||||
|
castShadows: castShadows,
|
||||||
|
position: position ?? Vector3(0, 1, 0),
|
||||||
|
direction: direction ?? Vector3(0, -1, 0),
|
||||||
|
falloffRadius: falloffRadius,
|
||||||
|
spotLightConeInner: spotLightConeInner,
|
||||||
|
spotLightConeOuter: spotLightConeOuter,
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
// see filament Manipulator.h for more details
|
||||||
|
@Deprecated(
|
||||||
|
"This is used the native pointer manipulator Prefer ThermionGestureHandler instead")
|
||||||
|
enum ManipulatorMode { ORBIT, MAP, FREE_FLIGHT }
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
abstract class MaterialInstance {
|
||||||
|
Future setDepthWriteEnabled(bool enabled);
|
||||||
|
Future setDepthCullingEnabled(bool enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AlphaMode { OPAQUE, MASK, BLEND }
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/shared_types/shared_types.dart';
|
||||||
|
|
||||||
|
typedef FilamentPickResult = ({ThermionEntity entity, double x, double y});
|
||||||
|
typedef ThermionPickResult = FilamentPickResult;
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// copied from filament/backened/DriverEnums.h
|
||||||
|
enum PrimitiveType {
|
||||||
|
// don't change the enums values (made to match GL)
|
||||||
|
POINTS, //!< points
|
||||||
|
LINES, //!< lines
|
||||||
|
UNUSED1,
|
||||||
|
LINE_STRIP, //!< line strip
|
||||||
|
TRIANGLES, //!< triangles
|
||||||
|
TRIANGLE_STRIP, //!< triangle strip
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
enum ShadowType {
|
||||||
|
PCF, //!< percentage-closer filtered shadows (default)
|
||||||
|
VSM, //!< variance shadows
|
||||||
|
DPCF, //!< PCF with contact hardening simulation
|
||||||
|
PCSS, //!< PCF with soft shadows and contact hardening
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
library shared_types;
|
||||||
|
|
||||||
|
export 'material.dart';
|
||||||
|
export 'texture.dart';
|
||||||
|
export 'entities.dart';
|
||||||
|
export 'light.dart';
|
||||||
|
export 'shadow.dart';
|
||||||
|
export 'manipulator.dart';
|
||||||
|
export 'pick_result.dart';
|
||||||
|
export 'primitive.dart';
|
||||||
|
export 'texture_details.dart';
|
||||||
|
export 'tone_mapper.dart';
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
abstract class ThermionTexture {
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
///
|
||||||
|
/// This represents the backing "surface" that we render into.
|
||||||
|
/// "Texture" here is a misnomer as it is only a render target texture on certain platforms.
|
||||||
|
///
|
||||||
|
class TextureDetails {
|
||||||
|
final int textureId;
|
||||||
|
|
||||||
|
// both width and height are in physical, not logical pixels
|
||||||
|
final int width;
|
||||||
|
final int height;
|
||||||
|
|
||||||
|
TextureDetails(
|
||||||
|
{required this.textureId, required this.width, required this.height});
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
enum ToneMapper { ACES, FILMIC, LINEAR }
|
||||||
963
thermion_dart/lib/thermion_dart/viewer/thermion_viewer_base.dart
Normal file
963
thermion_dart/lib/thermion_dart/viewer/thermion_viewer_base.dart
Normal file
@@ -0,0 +1,963 @@
|
|||||||
|
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||||
|
|
||||||
|
import 'shared_types/shared_types.dart';
|
||||||
|
export 'shared_types/shared_types.dart';
|
||||||
|
|
||||||
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||||
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
|
import 'dart:async';
|
||||||
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
|
|
||||||
|
const double kNear = 0.05;
|
||||||
|
const double kFar = 1000.0;
|
||||||
|
const double kFocalLength = 28.0;
|
||||||
|
|
||||||
|
abstract class ThermionViewer {
|
||||||
|
///
|
||||||
|
/// A Future that resolves when the underlying rendering context has been successfully created.
|
||||||
|
///
|
||||||
|
Future<bool> get initialized;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The current dimensions of the viewport (in physical pixels).
|
||||||
|
///
|
||||||
|
var viewportDimensions = (0.0, 0.0);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The current ratio of logical to physical pixels.
|
||||||
|
///
|
||||||
|
late double pixelRatio;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The result(s) of calling [pick] (see below).
|
||||||
|
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
||||||
|
/// If [pick] is called without an active subscription to this stream, the results will be silently discarded.
|
||||||
|
///
|
||||||
|
Stream<FilamentPickResult> get pickResult;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The result(s) of calling [pickGizmo] (see below).
|
||||||
|
///
|
||||||
|
Stream<FilamentPickResult> get gizmoPickResult;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// A Stream containing entities added/removed to/from to the scene.
|
||||||
|
///
|
||||||
|
Stream<SceneUpdateEvent> get sceneUpdated;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Whether the controller is currently rendering at [framerate].
|
||||||
|
///
|
||||||
|
bool get rendering;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set to true to continuously render the scene at the framerate specified by [setFrameRate] (60 fps by default).
|
||||||
|
///
|
||||||
|
Future setRendering(bool render);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Render a single frame immediately.
|
||||||
|
///
|
||||||
|
Future render();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Requests a single frame to be rendered. This is only intended to be used internally.
|
||||||
|
///
|
||||||
|
void requestFrame();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Render a single frame and copy the pixel buffer to [out].
|
||||||
|
///
|
||||||
|
Future<Uint8List> capture();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
|
||||||
|
///
|
||||||
|
Future setFrameRate(int framerate);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Destroys/disposes the viewer (including the entire scene). You cannot use the viewer after calling this method.
|
||||||
|
///
|
||||||
|
Future dispose();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the background image to [path] (which should have a file extension .png, .jpg, or .ktx).
|
||||||
|
/// This will be rendered at the maximum depth (i.e. behind all other objects including the skybox).
|
||||||
|
/// If [fillHeight] is false, the image will be rendered at its original size. Note this may cause issues with pixel density so be sure to specify the correct resolution
|
||||||
|
/// If [fillHeight] is true, the image will be stretched/compressed to fit the height of the viewport.
|
||||||
|
///
|
||||||
|
Future setBackgroundImage(String path, {bool fillHeight = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Moves the background image to the relative offset from the origin (bottom-left) specified by [x] and [y].
|
||||||
|
/// If [clamp] is true, the image cannot be positioned outside the bounds of the viewport.
|
||||||
|
///
|
||||||
|
Future setBackgroundImagePosition(double x, double y, {bool clamp = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes the background image.
|
||||||
|
///
|
||||||
|
Future clearBackgroundImage();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox).
|
||||||
|
///
|
||||||
|
Future setBackgroundColor(double r, double g, double b, double alpha);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Load a skybox from [skyboxPath] (which must be a .ktx file)
|
||||||
|
///
|
||||||
|
Future loadSkybox(String skyboxPath);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes the skybox from the scene.
|
||||||
|
///
|
||||||
|
Future removeSkybox();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Creates an indirect light by loading the reflections/irradiance from the KTX file.
|
||||||
|
/// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced.
|
||||||
|
///
|
||||||
|
Future loadIbl(String lightingPath, {double intensity = 30000});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Creates a indirect light with the given color.
|
||||||
|
/// Only one indirect light can be active at any given time; if an indirect light has already been loaded, it will be replaced.
|
||||||
|
///
|
||||||
|
Future createIbl(double r, double g, double b, double intensity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Rotates the IBL & skybox.
|
||||||
|
///
|
||||||
|
Future rotateIbl(Matrix3 rotation);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes the image-based light from the scene.
|
||||||
|
///
|
||||||
|
Future removeIbl();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Add a light to the scene.
|
||||||
|
/// See LightManager.h for details
|
||||||
|
/// Note that [sunAngularRadius] is in degrees,
|
||||||
|
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
|
||||||
|
///
|
||||||
|
@Deprecated(
|
||||||
|
"This will be removed in future versions. Use addDirectLight instead.")
|
||||||
|
Future<ThermionEntity> addLight(
|
||||||
|
LightType type,
|
||||||
|
double colour,
|
||||||
|
double intensity,
|
||||||
|
double posX,
|
||||||
|
double posY,
|
||||||
|
double posZ,
|
||||||
|
double dirX,
|
||||||
|
double dirY,
|
||||||
|
double dirZ,
|
||||||
|
{double falloffRadius = 1.0,
|
||||||
|
double spotLightConeInner = pi / 8,
|
||||||
|
double spotLightConeOuter = pi / 4,
|
||||||
|
double sunAngularRadius = 0.545,
|
||||||
|
double sunHaloSize = 10.0,
|
||||||
|
double sunHaloFallof = 80.0,
|
||||||
|
bool castShadows = true});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Adds a direct light to the scene.
|
||||||
|
/// See LightManager.h for details
|
||||||
|
/// Note that [sunAngularRadius] is in degrees,
|
||||||
|
/// whereas [spotLightConeInner] and [spotLightConeOuter] are in radians
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> addDirectLight(DirectLight light);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Remove a light from the scene.
|
||||||
|
///
|
||||||
|
Future removeLight(ThermionEntity light);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Remove all lights (excluding IBL) from the scene.
|
||||||
|
///
|
||||||
|
Future clearLights();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Load the .glb asset at the given path and insert into the scene.
|
||||||
|
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
|
||||||
|
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
|
||||||
|
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> loadGlb(String path,
|
||||||
|
{int numInstances = 1, bool keepData = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Load the .glb asset from the specified buffer and insert into the scene.
|
||||||
|
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
|
||||||
|
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
|
||||||
|
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data,
|
||||||
|
{int numInstances = 1,
|
||||||
|
bool keepData = false,
|
||||||
|
int priority = 4,
|
||||||
|
int layer = 0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Create a new instance of [entity].
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> createInstance(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the number of instances of the asset associated with [entity].
|
||||||
|
///
|
||||||
|
Future<int> getInstanceCount(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns all instances of [entity].
|
||||||
|
///
|
||||||
|
Future<List<ThermionEntity>> getInstances(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Load the .gltf asset at the given path and insert into the scene.
|
||||||
|
/// [relativeResourcePath] is the folder path where the glTF resources are stored;
|
||||||
|
/// this is usually the parent directory of the .gltf file itself.
|
||||||
|
///
|
||||||
|
/// See [loadGlb] for an explanation of [keepData].
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||||
|
{bool keepData = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future panStart(double x, double y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future panUpdate(double x, double y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future panEnd();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future rotateStart(double x, double y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future rotateUpdate(double x, double y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future rotateEnd();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the weights for all morph targets in [entity] to [weights].
|
||||||
|
/// Note that [weights] must contain values for ALL morph targets, but no exception will be thrown if you don't do so (you'll just get incorrect results).
|
||||||
|
/// If you only want to set one value, set all others to zero (check [getMorphTargetNames] if you need the get a list of all morph targets).
|
||||||
|
/// IMPORTANT - this accepts the actual ThermionEntity with the relevant morph targets (unlike [getMorphTargetNames], which uses the parent entity and the child mesh name).
|
||||||
|
/// Use [getChildEntityByName] if you are setting the weights for a child mesh.
|
||||||
|
///
|
||||||
|
Future setMorphTargetWeights(ThermionEntity entity, List<double> weights);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the names of all morph targets for the child renderable [childEntity] under [entity].
|
||||||
|
///
|
||||||
|
Future<List<String>> getMorphTargetNames(
|
||||||
|
ThermionEntity entity, ThermionEntity childEntity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the names of all bones for the armature at [skinIndex] under the specified [entity].
|
||||||
|
///
|
||||||
|
Future<List<String>> getBoneNames(ThermionEntity entity, {int skinIndex = 0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the names of all glTF animations embedded in the specified entity.
|
||||||
|
///
|
||||||
|
Future<List<String>> getAnimationNames(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the length (in seconds) of the animation at the given index.
|
||||||
|
///
|
||||||
|
Future<double> getAnimationDuration(
|
||||||
|
ThermionEntity entity, int animationIndex);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Animate the morph targets in [entity]. See [MorphTargetAnimation] for an explanation as to how to construct the animation frame data.
|
||||||
|
/// This method will check the morph target names specified in [animation] against the morph target names that actually exist exist under [meshName] in [entity],
|
||||||
|
/// throwing an exception if any cannot be found.
|
||||||
|
/// It is permissible for [animation] to omit any targets that do exist under [meshName]; these simply won't be animated.
|
||||||
|
///
|
||||||
|
Future setMorphAnimationData(
|
||||||
|
ThermionEntity entity, MorphAnimationData animation,
|
||||||
|
{List<String>? targetMeshNames});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Clear all current morph animations for [entity].
|
||||||
|
///
|
||||||
|
Future clearMorphAnimationData(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Resets all bones in the given entity to their rest pose.
|
||||||
|
/// This should be done before every call to addBoneAnimation.
|
||||||
|
///
|
||||||
|
Future resetBones(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Enqueues and plays the [animation] for the specified bone(s).
|
||||||
|
/// By default, frame data is interpreted as being in *parent* bone space;
|
||||||
|
/// a 45 degree around Y means the bone will rotate 45 degrees around the
|
||||||
|
/// Y axis of the parent bone *in its current orientation*.
|
||||||
|
/// (i.e NOT the parent bone's rest position!).
|
||||||
|
/// Currently, only [Space.ParentBone] and [Space.Model] are supported; if you want
|
||||||
|
/// to transform to another space, you will need to do so manually.
|
||||||
|
///
|
||||||
|
/// [fadeInInSecs]/[fadeOutInSecs]/[maxDelta] are used to cross-fade between
|
||||||
|
/// the current active glTF animation ("animation1") and the animation you
|
||||||
|
/// set via this method ("animation2"). The bone orientations will be
|
||||||
|
/// linearly interpolated between animation1 and animation2; at time 0,
|
||||||
|
/// the orientation will be 100% animation1, at time [fadeInInSecs], the
|
||||||
|
/// animation will be ((1 - maxDelta) * animation1) + (maxDelta * animation2).
|
||||||
|
/// This will be applied in reverse after [fadeOutInSecs].
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future addBoneAnimation(ThermionEntity entity, BoneAnimationData animation,
|
||||||
|
{int skinIndex = 0,
|
||||||
|
double fadeInInSecs = 0.0,
|
||||||
|
double fadeOutInSecs = 0.0,
|
||||||
|
double maxDelta = 1.0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the entity representing the bone at [boneIndex]/[skinIndex].
|
||||||
|
/// The returned entity is only intended for use with [getWorldTransform].
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> getBone(ThermionEntity parent, int boneIndex,
|
||||||
|
{int skinIndex = 0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the local (relative to parent) transform for [entity].
|
||||||
|
///
|
||||||
|
Future<Matrix4> getLocalTransform(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the world transform for [entity].
|
||||||
|
///
|
||||||
|
Future<Matrix4> getWorldTransform(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the inverse bind (pose) matrix for the bone.
|
||||||
|
/// Note that [parent] must be the ThermionEntity returned by [loadGlb/loadGltf], not any other method ([getChildEntity] etc).
|
||||||
|
/// This is because all joint information is internally stored with the parent entity.
|
||||||
|
///
|
||||||
|
Future<Matrix4> getInverseBindMatrix(ThermionEntity parent, int boneIndex,
|
||||||
|
{int skinIndex = 0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the transform (relative to its parent) for [entity].
|
||||||
|
///
|
||||||
|
Future setTransform(ThermionEntity entity, Matrix4 transform);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Updates the bone matrices for [entity] (which must be the ThermionEntity
|
||||||
|
/// returned by [loadGlb/loadGltf]).
|
||||||
|
/// Under the hood, this just calls [updateBoneMatrices] on the Animator
|
||||||
|
/// instance of the relevant FilamentInstance (which uses the local
|
||||||
|
/// bone transform and the inverse bind matrix to set the bone matrix).
|
||||||
|
///
|
||||||
|
Future updateBoneMatrices(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Directly set the bone matrix for the bone at the given index.
|
||||||
|
/// Don't call this manually unless you know what you're doing.
|
||||||
|
///
|
||||||
|
Future setBoneTransform(
|
||||||
|
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
||||||
|
{int skinIndex = 0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes/destroys the specified entity from the scene.
|
||||||
|
/// [entity] will no longer be a valid handle after this method is called; ensure you immediately discard all references once this method is complete.
|
||||||
|
///
|
||||||
|
Future removeEntity(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes/destroys all renderable entities from the scene (including cameras).
|
||||||
|
/// All [ThermionEntity] handles will no longer be valid after this method is called; ensure you immediately discard all references to all entities once this method is complete.
|
||||||
|
///
|
||||||
|
Future clearEntities();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future zoomBegin();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future zoomUpdate(double x, double y, double z);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||||
|
///
|
||||||
|
Future zoomEnd();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||||
|
///
|
||||||
|
Future playAnimation(ThermionEntity entity, int index,
|
||||||
|
{bool loop = false,
|
||||||
|
bool reverse = false,
|
||||||
|
bool replaceActive = true,
|
||||||
|
double crossfade = 0.0,
|
||||||
|
double startOffset = 0.0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||||
|
///
|
||||||
|
Future playAnimationByName(ThermionEntity entity, String name,
|
||||||
|
{bool loop = false,
|
||||||
|
bool reverse = false,
|
||||||
|
bool replaceActive = true,
|
||||||
|
double crossfade = 0.0});
|
||||||
|
|
||||||
|
Future setAnimationFrame(
|
||||||
|
ThermionEntity entity, int index, int animationFrame);
|
||||||
|
|
||||||
|
Future stopAnimation(ThermionEntity entity, int animationIndex);
|
||||||
|
Future stopAnimationByName(ThermionEntity entity, String name);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the current scene camera to the glTF camera under [name] in [entity].
|
||||||
|
///
|
||||||
|
Future setCamera(ThermionEntity entity, String? name);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the current scene camera to the main camera (which is always available and added to every scene by default).
|
||||||
|
///
|
||||||
|
Future setMainCamera();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the entity associated with the main camera. You probably never need this; use getMainCamera instead.
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> getMainCameraEntity();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns the entity associated with the main camera. You probably never need this; use getMainCamera instead.
|
||||||
|
///
|
||||||
|
Future<Camera> getMainCamera();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the horizontal field of view (if [horizontal] is true) or vertical field of view for the currently active camera to [degrees].
|
||||||
|
/// The aspect ratio of the current viewport is used.
|
||||||
|
///
|
||||||
|
Future setCameraFov(double degrees, {bool horizontal = true});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the field of view (in degrees).
|
||||||
|
///
|
||||||
|
Future<double> getCameraFov(bool horizontal);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the tone mapping (requires postprocessing).
|
||||||
|
///
|
||||||
|
Future setToneMapping(ToneMapper mapper);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the strength of the bloom.
|
||||||
|
///
|
||||||
|
Future setBloom(double bloom);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the focal length of the camera. Default value is 28.0.
|
||||||
|
///
|
||||||
|
Future setCameraFocalLength(double focalLength);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the distance (in world units) to the near/far planes for the active camera. Default values are 0.05/1000.0. See Camera.h for details.
|
||||||
|
///
|
||||||
|
Future setCameraCulling(double near, double far);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the distance (in world units) to the near plane for the active camera.
|
||||||
|
///
|
||||||
|
@Deprecated("Use getCameraNear")
|
||||||
|
Future<double> getCameraCullingNear();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the distance (in world units) to the near plane for the active camera.
|
||||||
|
///
|
||||||
|
Future<double> getCameraNear();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the distance (in world units) to the far culling plane for the active camera.
|
||||||
|
///
|
||||||
|
Future<double> getCameraCullingFar();
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future setCameraLensProjection(
|
||||||
|
{double near = kNear,
|
||||||
|
double far = kFar,
|
||||||
|
double? aspect,
|
||||||
|
double focalLength = kFocalLength});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the focus distance for the camera.
|
||||||
|
///
|
||||||
|
Future setCameraFocusDistance(double focusDistance);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera position in world space.
|
||||||
|
///
|
||||||
|
Future<Vector3> getCameraPosition();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera's model matrix.
|
||||||
|
///
|
||||||
|
Future<Matrix4> getCameraModelMatrix();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera's view matrix. See Camera.h for more details.
|
||||||
|
///
|
||||||
|
Future<Matrix4> getCameraViewMatrix();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera's projection matrix. See Camera.h for more details.
|
||||||
|
///
|
||||||
|
Future<Matrix4> getCameraProjectionMatrix();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera's culling projection matrix. See Camera.h for more details.
|
||||||
|
///
|
||||||
|
Future<Matrix4> getCameraCullingProjectionMatrix();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera's culling frustum in world space. Returns a (vector_math) [Frustum] instance where plane0-plane6 define the left, right, bottom, top, far and near planes respectively.
|
||||||
|
/// See Camera.h and (filament) Frustum.h for more details.
|
||||||
|
///
|
||||||
|
Future<Frustum> getCameraFrustum();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the camera position in world space. Note this is not persistent - any viewport navigation will reset the camera transform.
|
||||||
|
///
|
||||||
|
Future setCameraPosition(double x, double y, double z);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Get the camera rotation matrix.
|
||||||
|
///
|
||||||
|
Future<Matrix3> getCameraRotation();
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Repositions the camera to the last vertex of the bounding box of [entity], looking at the penultimate vertex.
|
||||||
|
///
|
||||||
|
Future moveCameraToAsset(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Enables/disables frustum culling.
|
||||||
|
///
|
||||||
|
Future setViewFrustumCulling(bool enabled);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the camera exposure.
|
||||||
|
///
|
||||||
|
Future setCameraExposure(
|
||||||
|
double aperture, double shutterSpeed, double sensitivity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Rotate the camera by [rads] around the given axis.
|
||||||
|
///
|
||||||
|
Future setCameraRotation(Quaternion quaternion);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the camera model matrix.
|
||||||
|
///
|
||||||
|
@Deprecated("Will be superseded by setCameraModelMatrix4")
|
||||||
|
Future setCameraModelMatrix(List<double> matrix);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the camera model matrix.
|
||||||
|
///
|
||||||
|
Future setCameraModelMatrix4(Matrix4 matrix);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the `baseColorFactor` property for the material at index [materialIndex] in [entity] under node [meshName] to [color].
|
||||||
|
///
|
||||||
|
@Deprecated("Use setMaterialPropertyFloat4 instead")
|
||||||
|
Future setMaterialColor(ThermionEntity entity, String meshName,
|
||||||
|
int materialIndex, double r, double g, double b, double a);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
|
||||||
|
/// [entity] must have a Renderable attached.
|
||||||
|
///
|
||||||
|
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName,
|
||||||
|
int materialIndex, double f1, double f2, double f3, double f4);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
|
||||||
|
/// [entity] must have a Renderable attached.
|
||||||
|
///
|
||||||
|
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName,
|
||||||
|
int materialIndex, double value);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the material property [propertyName] under material [materialIndex] for [entity] to [value].
|
||||||
|
/// [entity] must have a Renderable attached.
|
||||||
|
///
|
||||||
|
Future setMaterialPropertyInt(
|
||||||
|
ThermionEntity entity, String propertyName, int materialIndex, int value);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Scale [entity] to fit within the unit cube.
|
||||||
|
///
|
||||||
|
Future transformToUnitCube(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Directly sets the world space position for [entity] to the given coordinates.
|
||||||
|
///
|
||||||
|
Future setPosition(ThermionEntity entity, double x, double y, double z);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set the world space position for [lightEntity] to the given coordinates.
|
||||||
|
///
|
||||||
|
Future setLightPosition(
|
||||||
|
ThermionEntity lightEntity, double x, double y, double z);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the world space direction for [lightEntity] to the given vector.
|
||||||
|
///
|
||||||
|
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Directly sets the scale for [entity], skipping all collision detection.
|
||||||
|
///
|
||||||
|
Future setScale(ThermionEntity entity, double scale);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Directly sets the rotation for [entity] to [rads] around the axis {x,y,z}, skipping all collision detection.
|
||||||
|
///
|
||||||
|
Future setRotation(
|
||||||
|
ThermionEntity entity, double rads, double x, double y, double z);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Queues an update to the worldspace position for [entity] to {x,y,z}.
|
||||||
|
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
||||||
|
///
|
||||||
|
Future queuePositionUpdate(
|
||||||
|
ThermionEntity entity, double x, double y, double z,
|
||||||
|
{bool relative = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// TODO
|
||||||
|
///
|
||||||
|
Future queuePositionUpdateFromViewportCoords(
|
||||||
|
ThermionEntity entity, double x, double y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// TODO
|
||||||
|
///
|
||||||
|
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity,
|
||||||
|
double viewportX, double viewportY, double x, double y, double z);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Queues an update to the worldspace rotation for [entity].
|
||||||
|
/// The actual update will occur on the next frame, and will be subject to collision detection.
|
||||||
|
///
|
||||||
|
Future queueRotationUpdate(
|
||||||
|
ThermionEntity entity, double rads, double x, double y, double z,
|
||||||
|
{bool relative = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Same as [queueRotationUpdate].
|
||||||
|
///
|
||||||
|
Future queueRotationUpdateQuat(ThermionEntity entity, Quaternion quat,
|
||||||
|
{bool relative = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Enable/disable postprocessing (disabled by default).
|
||||||
|
///
|
||||||
|
Future setPostProcessing(bool enabled);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Enable/disable shadows (disabled by default).
|
||||||
|
///
|
||||||
|
Future setShadowsEnabled(bool enabled);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set shadow type.
|
||||||
|
///
|
||||||
|
Future setShadowType(ShadowType shadowType);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set soft shadow options (ShadowType DPCF and PCSS)
|
||||||
|
///
|
||||||
|
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Set antialiasing options.
|
||||||
|
///
|
||||||
|
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the rotation for [entity] to the specified quaternion.
|
||||||
|
///
|
||||||
|
Future setRotationQuat(ThermionEntity entity, Quaternion rotation);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Reveal the node [meshName] under [entity]. Only applicable if [hide] had previously been called; this is a no-op otherwise.
|
||||||
|
///
|
||||||
|
Future reveal(ThermionEntity entity, String? meshName);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// If [meshName] is provided, hide the node [meshName] under [entity], otherwise hide the root node for [entity].
|
||||||
|
/// The entity still exists in memory, but is no longer being rendered into the scene. Call [reveal] to re-commence rendering.
|
||||||
|
///
|
||||||
|
Future hide(ThermionEntity entity, String? meshName);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Used to select the entity in the scene at the given viewport coordinates.
|
||||||
|
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||||
|
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
|
||||||
|
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||||
|
///
|
||||||
|
void pick(int x, int y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Used to test whether a Gizmo is at the given viewport coordinates.
|
||||||
|
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||||
|
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method.
|
||||||
|
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||||
|
///
|
||||||
|
void pickGizmo(int x, int y);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
|
||||||
|
///
|
||||||
|
String? getNameForEntity(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the options for manipulating the camera via the viewport.
|
||||||
|
/// ManipulatorMode.FREE_FLIGHT and ManipulatorMode.MAP are currently unsupported and will throw an exception.
|
||||||
|
///
|
||||||
|
@Deprecated("Use ThermionGestureHandler instead")
|
||||||
|
Future setCameraManipulatorOptions(
|
||||||
|
{ManipulatorMode mode = ManipulatorMode.ORBIT,
|
||||||
|
double orbitSpeedX = 0.01,
|
||||||
|
double orbitSpeedY = 0.01,
|
||||||
|
double zoomSpeed = 0.01});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Returns all child entities under [parent].
|
||||||
|
///
|
||||||
|
Future<List<ThermionEntity>> getChildEntities(
|
||||||
|
ThermionEntity parent, bool renderableOnly);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Finds the child entity named [childName] associated with the given parent.
|
||||||
|
/// Usually, [parent] will be the return value from [loadGlb]/[loadGltf] and [childName] will be the name of a node/mesh.
|
||||||
|
///
|
||||||
|
Future<ThermionEntity> getChildEntity(
|
||||||
|
ThermionEntity parent, String childName);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// List the name of all child entities under the given entity.
|
||||||
|
///
|
||||||
|
Future<List<String>> getChildEntityNames(ThermionEntity entity,
|
||||||
|
{bool renderableOnly = true});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// If [recording] is set to true, each frame the framebuffer/texture will be written to /tmp/output_*.png.
|
||||||
|
/// This will impact performance; handle with care.
|
||||||
|
///
|
||||||
|
Future setRecording(bool recording);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the output directory where recorded PNGs will be placed.
|
||||||
|
///
|
||||||
|
Future setRecordingOutputDirectory(String outputDirectory);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// An [entity] will only be animatable after an animation component is attached.
|
||||||
|
/// Any calls to [playAnimation]/[setBoneAnimation]/[setMorphAnimation] will have no visual effect until [addAnimationComponent] has been called on the instance.
|
||||||
|
///
|
||||||
|
Future addAnimationComponent(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes an animation component from [entity].
|
||||||
|
///
|
||||||
|
Future removeAnimationComponent(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Makes [entity] collidable.
|
||||||
|
/// This allows you to call [testCollisions] with any other entity ("entity B") to see if [entity] has collided with entity B. The callback will be invoked if so.
|
||||||
|
/// Alternatively, if [affectsTransform] is true and this entity collides with another entity, any queued position updates to the latter entity will be ignored.
|
||||||
|
///
|
||||||
|
Future addCollisionComponent(ThermionEntity entity,
|
||||||
|
{void Function(int entityId1, int entityId2)? callback,
|
||||||
|
bool affectsTransform = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes the collision component from [entity], meaning this will no longer be tested when [testCollisions] or [queuePositionUpdate] is called with another entity.
|
||||||
|
///
|
||||||
|
Future removeCollisionComponent(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Creates a (renderable) entity with the specified geometry and adds to the scene.
|
||||||
|
/// If [keepData] is true, the source data will not be released.
|
||||||
|
///
|
||||||
|
Future createGeometry(Geometry geometry,
|
||||||
|
{MaterialInstance? materialInstance, bool keepData = false});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the parent entity of [entity]. Returns null if the entity has no parent.
|
||||||
|
///
|
||||||
|
Future<ThermionEntity?> getParent(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the ancestor (ultimate parent) entity of [entity]. Returns null if the entity has no parent.
|
||||||
|
///
|
||||||
|
Future<ThermionEntity?> getAncestor(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the parent transform of [child] to [parent].
|
||||||
|
///
|
||||||
|
Future setParent(ThermionEntity child, ThermionEntity parent,
|
||||||
|
{bool preserveScaling});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Test all collidable entities against this entity to see if any have collided.
|
||||||
|
/// This method returns void; the relevant callback passed to [addCollisionComponent] will be fired if a collision is detected.
|
||||||
|
///
|
||||||
|
Future testCollisions(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Sets the draw priority for the given entity. See RenderableManager.h for more details.
|
||||||
|
///
|
||||||
|
Future setPriority(ThermionEntity entityId, int priority);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// The gizmo for translating/rotating objects. Only one gizmo is present in the scene.
|
||||||
|
///
|
||||||
|
AbstractGizmo? get gizmo;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Register a callback to be invoked when this viewer is disposed.
|
||||||
|
///
|
||||||
|
void onDispose(Future Function() callback);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Gets the 2D bounding box (in viewport coordinates) for the given entity.
|
||||||
|
///
|
||||||
|
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Filament assigns renderables to a numeric layer.
|
||||||
|
/// We place all scene assets in layer 0 (enabled by default), gizmos in layer 1 (enabled by default), world grid in layer 2 (disabled by default).
|
||||||
|
/// Use this method to toggle visibility of the respective layer.
|
||||||
|
///
|
||||||
|
Future setLayerVisibility(int layer, bool visible);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Assigns [entity] to visibility layer [layer].
|
||||||
|
///
|
||||||
|
Future setVisibilityLayer(ThermionEntity entity, int layer);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Show/hide the translation gizmo.
|
||||||
|
///
|
||||||
|
Future setGizmoVisibility(bool visible);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Renders an outline around [entity] with the given color.
|
||||||
|
///
|
||||||
|
Future setStencilHighlight(ThermionEntity entity,
|
||||||
|
{double r = 1.0, double g = 0.0, double b = 0.0});
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Removes the outline around [entity]. Noop if there was no highlight.
|
||||||
|
///
|
||||||
|
Future removeStencilHighlight(ThermionEntity entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Decodes the specified image data and creates a texture.
|
||||||
|
///
|
||||||
|
Future<ThermionTexture> createTexture(Uint8List data);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity,
|
||||||
|
{int materialIndex = 0, String parameterName = "baseColorMap"});
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future destroyTexture(covariant ThermionTexture texture);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future<MaterialInstance> createUbershaderMaterialInstance({
|
||||||
|
bool doubleSided = false,
|
||||||
|
bool unlit = false,
|
||||||
|
bool hasVertexColors = false,
|
||||||
|
bool hasBaseColorTexture = false,
|
||||||
|
bool hasNormalTexture = false,
|
||||||
|
bool hasOcclusionTexture = false,
|
||||||
|
bool hasEmissiveTexture = false,
|
||||||
|
bool useSpecularGlossiness = false,
|
||||||
|
AlphaMode alphaMode = AlphaMode.OPAQUE,
|
||||||
|
bool enableDiagnostics = false,
|
||||||
|
bool hasMetallicRoughnessTexture = false,
|
||||||
|
int metallicRoughnessUV = 0,
|
||||||
|
int baseColorUV = 0,
|
||||||
|
bool hasClearCoatTexture = false,
|
||||||
|
int clearCoatUV = 0,
|
||||||
|
bool hasClearCoatRoughnessTexture = false,
|
||||||
|
int clearCoatRoughnessUV = 0,
|
||||||
|
bool hasClearCoatNormalTexture = false,
|
||||||
|
int clearCoatNormalUV = 0,
|
||||||
|
bool hasClearCoat = false,
|
||||||
|
bool hasTransmission = false,
|
||||||
|
bool hasTextureTransforms = false,
|
||||||
|
int emissiveUV = 0,
|
||||||
|
int aoUV = 0,
|
||||||
|
int normalUV = 0,
|
||||||
|
bool hasTransmissionTexture = false,
|
||||||
|
int transmissionUV = 0,
|
||||||
|
bool hasSheenColorTexture = false,
|
||||||
|
int sheenColorUV = 0,
|
||||||
|
bool hasSheenRoughnessTexture = false,
|
||||||
|
int sheenRoughnessUV = 0,
|
||||||
|
bool hasVolumeThicknessTexture = false,
|
||||||
|
int volumeThicknessUV = 0,
|
||||||
|
bool hasSheen = false,
|
||||||
|
bool hasIOR = false,
|
||||||
|
bool hasVolume = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future destroyMaterialInstance(covariant MaterialInstance materialInstance);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future<MaterialInstance> createUnlitMaterialInstance();
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future<MaterialInstance?> getMaterialInstanceAt(
|
||||||
|
ThermionEntity entity, int index);
|
||||||
|
}
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
import 'package:thermion_dart/thermion_dart/thermion_viewer.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/events.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/shared_types/camera.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/viewer/thermion_viewer_base.dart';
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import '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';
|
||||||
|
|
||||||
typedef ThermionViewerImpl = ThermionViewerStub;
|
|
||||||
|
|
||||||
class ThermionViewerStub extends ThermionViewer {
|
class ThermionViewerStub extends ThermionViewer {
|
||||||
@override
|
@override
|
||||||
Future addAnimationComponent(ThermionEntity entity) {
|
Future addAnimationComponent(ThermionEntity entity) {
|
||||||
@@ -73,13 +75,6 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future createGeometry(List<double> vertices, List<int> indices,
|
|
||||||
{String? materialPath,
|
|
||||||
PrimitiveType primitiveType = PrimitiveType.TRIANGLES}) {
|
|
||||||
// TODO: implement createGeometry
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ThermionEntity> createInstance(ThermionEntity entity) {
|
Future<ThermionEntity> createInstance(ThermionEntity entity) {
|
||||||
@@ -220,12 +215,6 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<ThermionEntity> getMainCamera() {
|
|
||||||
// TODO: implement getMainCamera
|
|
||||||
throw UnimplementedError();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<List<String>> getMorphTargetNames(
|
Future<List<String>> getMorphTargetNames(
|
||||||
ThermionEntity entity, ThermionEntity childEntity) {
|
ThermionEntity entity, ThermionEntity childEntity) {
|
||||||
@@ -265,19 +254,6 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
// TODO: implement initialized
|
// TODO: implement initialized
|
||||||
Future<bool> get initialized => throw UnimplementedError();
|
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
|
@override
|
||||||
Future loadIbl(String lightingPath, {double intensity = 30000}) {
|
Future loadIbl(String lightingPath, {double intensity = 30000}) {
|
||||||
// TODO: implement loadIbl
|
// TODO: implement loadIbl
|
||||||
@@ -333,7 +309,8 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
{bool loop = false,
|
{bool loop = false,
|
||||||
bool reverse = false,
|
bool reverse = false,
|
||||||
bool replaceActive = true,
|
bool replaceActive = true,
|
||||||
double crossfade = 0.0}) {
|
double crossfade = 0.0,
|
||||||
|
double startOffset=0.0}) {
|
||||||
// TODO: implement playAnimation
|
// TODO: implement playAnimation
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
@@ -453,10 +430,6 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
// TODO: implement scene
|
|
||||||
Scene get scene => throw UnimplementedError();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future setAnimationFrame(
|
Future setAnimationFrame(
|
||||||
ThermionEntity entity, int index, int animationFrame) {
|
ThermionEntity entity, int index, int animationFrame) {
|
||||||
@@ -534,7 +507,7 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future setCameraFov(double degrees, double width, double height) {
|
Future setCameraFov(double degrees, {bool horizontal=true}) {
|
||||||
// TODO: implement setCameraFov
|
// TODO: implement setCameraFov
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
@@ -606,7 +579,7 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future setParent(ThermionEntity child, ThermionEntity parent) {
|
Future setParent(ThermionEntity child, ThermionEntity parent, { bool preserveScaling = false}) {
|
||||||
// TODO: implement setParent
|
// TODO: implement setParent
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
@@ -749,4 +722,249 @@ class ThermionViewerStub extends ThermionViewer {
|
|||||||
// TODO: implement setSoftShadowOptions
|
// TODO: implement setSoftShadowOptions
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> capture() {
|
||||||
|
// TODO: implement capture
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Aabb2> getBoundingBox(ThermionEntity entity) {
|
||||||
|
// TODO: implement getBoundingBox
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCameraFov(bool horizontal) {
|
||||||
|
// TODO: implement getCameraFov
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity, double viewportX, double viewportY, double x, double y, double z) {
|
||||||
|
// TODO: implement queueRelativePositionUpdateWorldAxis
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLayerEnabled(int layer, bool enabled) {
|
||||||
|
// TODO: implement setLayerEnabled
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future createIbl(double r, double g, double b, double intensity) {
|
||||||
|
// TODO: implement createIbl
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement gizmoPickResult
|
||||||
|
Stream<FilamentPickResult> get gizmoPickResult => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void pickGizmo(int x, int y) {
|
||||||
|
// TODO: implement pickGizmo
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setGizmoVisibility(bool visible) {
|
||||||
|
// TODO: implement setGizmoVisibility
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity?> getAncestor(ThermionEntity entity) {
|
||||||
|
// TODO: implement getAncestor
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queuePositionUpdateFromViewportCoords(ThermionEntity entity, double x, double y) {
|
||||||
|
// TODO: implement queuePositionUpdateFromViewportCoords
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeStencilHighlight(ThermionEntity entity) {
|
||||||
|
// TODO: implement removeStencilHighlight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) {
|
||||||
|
// TODO: implement setLightDirection
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLightPosition(ThermionEntity lightEntity, double x, double y, double z) {
|
||||||
|
// TODO: implement setLightPosition
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) {
|
||||||
|
// TODO: implement setStencilHighlight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCameraNear() {
|
||||||
|
// TODO: implement getCameraNear
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity) {
|
||||||
|
// TODO: implement getViewportBoundingBox
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraModelMatrix4(Matrix4 matrix) {
|
||||||
|
// TODO: implement setCameraModelMatrix4
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> loadGlb(String path, {int numInstances = 1, bool keepData = false}) {
|
||||||
|
// TODO: implement loadGlb
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath, {bool keepData = false}) {
|
||||||
|
// TODO: implement loadGltf
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) {
|
||||||
|
// TODO: implement setMaterialPropertyFloat
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, int materialIndex, double f1, double f2, double f3, double f4) {
|
||||||
|
// TODO: implement setMaterialPropertyFloat4
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement sceneUpdated
|
||||||
|
Stream<SceneUpdateEvent> get sceneUpdated => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> addDirectLight(DirectLight light) {
|
||||||
|
// TODO: implement addDirectLight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future applyTexture(covariant ThermionTexture texture, ThermionEntity entity, {int materialIndex = 0, String parameterName = "baseColorMap"}) {
|
||||||
|
// TODO: implement applyTexture
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionTexture> createTexture(Uint8List data) {
|
||||||
|
// TODO: implement createTexture
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MaterialInstance> createUbershaderMaterialInstance({bool doubleSided = false, bool unlit = false, bool hasVertexColors = false, bool hasBaseColorTexture = false, bool hasNormalTexture = false, bool hasOcclusionTexture = false, bool hasEmissiveTexture = false, bool useSpecularGlossiness = false, AlphaMode alphaMode = AlphaMode.OPAQUE, bool enableDiagnostics = false, bool hasMetallicRoughnessTexture = false, int metallicRoughnessUV = 0, int baseColorUV = 0, bool hasClearCoatTexture = false, int clearCoatUV = 0, bool hasClearCoatRoughnessTexture = false, int clearCoatRoughnessUV = 0, bool hasClearCoatNormalTexture = false, int clearCoatNormalUV = 0, bool hasClearCoat = false, bool hasTransmission = false, bool hasTextureTransforms = false, int emissiveUV = 0, int aoUV = 0, int normalUV = 0, bool hasTransmissionTexture = false, int transmissionUV = 0, bool hasSheenColorTexture = false, int sheenColorUV = 0, bool hasSheenRoughnessTexture = false, int sheenRoughnessUV = 0, bool hasVolumeThicknessTexture = false, int volumeThicknessUV = 0, bool hasSheen = false, bool hasIOR = false, bool hasVolume = false}) {
|
||||||
|
// TODO: implement createUbershaderMaterialInstance
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MaterialInstance> createUnlitMaterialInstance() {
|
||||||
|
// TODO: implement createUnlitMaterialInstance
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future destroyMaterialInstance(covariant MaterialInstance materialInstance) {
|
||||||
|
// TODO: implement destroyMaterialInstance
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future destroyTexture(covariant ThermionTexture texture) {
|
||||||
|
// TODO: implement destroyTexture
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future createGeometry(Geometry geometry, {MaterialInstance? materialInstance, bool keepData = false}) {
|
||||||
|
// TODO: implement createGeometry
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0}) {
|
||||||
|
// TODO: implement loadGlbFromBuffer
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) {
|
||||||
|
// TODO: implement setMaterialPropertyInt
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MaterialInstance?> getMaterialInstanceAt(ThermionEntity entity, int index) {
|
||||||
|
// TODO: implement getMaterialInstanceAt
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLayerVisibility(int layer, bool visible) {
|
||||||
|
// TODO: implement setLayerVisibility
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialDepthWrite(ThermionEntity entity, int materialIndex, bool enabled) {
|
||||||
|
// TODO: implement setMaterialDepthWrite
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setVisibilityLayer(ThermionEntity entity, int layer) {
|
||||||
|
// TODO: implement setVisibilityLayer
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void requestFrame() {
|
||||||
|
// TODO: implement requestFrame
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) {
|
||||||
|
// TODO: implement setCameraLensProjection
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> getMainCameraEntity() {
|
||||||
|
// TODO: implement getMainCameraEntity
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Camera> getMainCamera() {
|
||||||
|
// TODO: implement getMainCamera
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,7 +3,7 @@ library thermion_flutter_js;
|
|||||||
|
|
||||||
import 'dart:js_interop';
|
import 'dart:js_interop';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/compatibility/web/interop/thermion_viewer_js_shim.dart';
|
import 'package:thermion_dart/thermion_dart/viewer/web/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';
|
||||||
@@ -48,6 +48,11 @@ class ThermionViewerJSDartBridge {
|
|||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise render() => viewer.render().toJS;
|
JSPromise render() => viewer.render().toJS;
|
||||||
|
|
||||||
|
@JSExport()
|
||||||
|
JSPromise<JSUint8Array> capture() {
|
||||||
|
return viewer.capture().then((captured) => captured.toJS).toJS;
|
||||||
|
}
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise setFrameRate(int framerate) => viewer.setFrameRate(framerate).toJS;
|
JSPromise setFrameRate(int framerate) => viewer.setFrameRate(framerate).toJS;
|
||||||
|
|
||||||
@@ -161,9 +166,9 @@ class ThermionViewerJSDartBridge {
|
|||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise<JSNumber> loadGltf(String path, String relativeResourcePath,
|
JSPromise<JSNumber> loadGltf(String path, String relativeResourcePath,
|
||||||
{bool force = false}) {
|
{bool keepData = false}) {
|
||||||
return viewer
|
return viewer
|
||||||
.loadGltf(path, relativeResourcePath, force: force)
|
.loadGltf(path, relativeResourcePath, keepData: keepData)
|
||||||
.then((entity) => entity.toJS)
|
.then((entity) => entity.toJS)
|
||||||
.toJS;
|
.toJS;
|
||||||
}
|
}
|
||||||
@@ -339,16 +344,15 @@ class ThermionViewerJSDartBridge {
|
|||||||
{bool loop = false,
|
{bool loop = false,
|
||||||
bool reverse = false,
|
bool reverse = false,
|
||||||
bool replaceActive = true,
|
bool replaceActive = true,
|
||||||
double crossfade = 0.0}) =>
|
double crossfade = 0.0,
|
||||||
|
double startOffset = 0.0}) =>
|
||||||
viewer
|
viewer
|
||||||
.playAnimation(
|
.playAnimation(entity, index,
|
||||||
entity,
|
loop: loop,
|
||||||
index,
|
reverse: reverse,
|
||||||
loop: loop,
|
replaceActive: replaceActive,
|
||||||
reverse: reverse,
|
crossfade: crossfade,
|
||||||
replaceActive: replaceActive,
|
startOffset: startOffset)
|
||||||
crossfade: crossfade,
|
|
||||||
)
|
|
||||||
.toJS;
|
.toJS;
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
@@ -400,8 +404,16 @@ class ThermionViewerJSDartBridge {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise setCameraFov(double degrees, double width, double height) =>
|
JSPromise setParent(
|
||||||
viewer.setCameraFov(degrees, width, height).toJS;
|
ThermionEntity child, ThermionEntity parent, bool preserveScaling) {
|
||||||
|
return viewer
|
||||||
|
.setParent(child, parent, preserveScaling: preserveScaling)
|
||||||
|
.toJS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@JSExport()
|
||||||
|
JSPromise setCameraFov(double degrees, bool horizontal) =>
|
||||||
|
viewer.setCameraFov(degrees, horizontal: horizontal).toJS;
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise setToneMapping(int mapper) =>
|
JSPromise setToneMapping(int mapper) =>
|
||||||
@@ -523,9 +535,11 @@ class ThermionViewerJSDartBridge {
|
|||||||
// b,
|
// b,
|
||||||
// a,
|
// a,
|
||||||
// ).toJS;
|
// ).toJS;
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise transformToUnitCube(ThermionEntity entity) =>
|
JSPromise transformToUnitCube(ThermionEntity entity) =>
|
||||||
viewer.transformToUnitCube(entity).toJS;
|
viewer.transformToUnitCube(entity).toJS;
|
||||||
|
|
||||||
@JSExport()
|
@JSExport()
|
||||||
JSPromise setPosition(ThermionEntity entity, double x, double y, double z) =>
|
JSPromise setPosition(ThermionEntity entity, double x, double y, double z) =>
|
||||||
viewer.setPosition(entity, x, y, z).toJS;
|
viewer.setPosition(entity, x, y, z).toJS;
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import 'dart:js_interop';
|
import 'dart:js_interop';
|
||||||
import 'dart:js_interop_unsafe';
|
import 'dart:js_interop_unsafe';
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart/entities/abstract_gizmo.dart';
|
||||||
import 'package:thermion_dart/thermion_dart/scene.dart';
|
import 'package:thermion_dart/thermion_dart/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_impl.dart';
|
|
||||||
import 'package:vector_math/vector_math_64.dart';
|
import 'package:vector_math/vector_math_64.dart';
|
||||||
import 'thermion_viewer_js_shim.dart';
|
import 'thermion_viewer_js_shim.dart';
|
||||||
|
|
||||||
@@ -368,9 +369,11 @@ class ThermionViewerJS implements ThermionViewer {
|
|||||||
{bool loop = false,
|
{bool loop = false,
|
||||||
bool reverse = false,
|
bool reverse = false,
|
||||||
bool replaceActive = true,
|
bool replaceActive = true,
|
||||||
double crossfade = 0.0}) async {
|
double crossfade = 0.0,
|
||||||
|
double startOffset = 0.0}) async {
|
||||||
await _shim
|
await _shim
|
||||||
.playAnimation(entity, index, loop, reverse, replaceActive, crossfade)
|
.playAnimation(
|
||||||
|
entity, index, loop, reverse, replaceActive, crossfade, startOffset)
|
||||||
.toDart;
|
.toDart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,8 +423,8 @@ class ThermionViewerJS implements ThermionViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setCameraFov(double degrees, double width, double height) async {
|
Future<void> setCameraFov(double degrees, {bool horizontal = true}) async {
|
||||||
await _shim.setCameraFov(degrees, width, height).toDart;
|
await _shim.setCameraFov(degrees, horizontal).toDart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -734,8 +737,9 @@ class ThermionViewerJS implements ThermionViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> setParent(ThermionEntity child, ThermionEntity parent) async {
|
Future<void> setParent(ThermionEntity child, ThermionEntity parent,
|
||||||
await _shim.setParent(child, parent).toDart;
|
{bool preserveScaling = false}) async {
|
||||||
|
await _shim.setParent(child, parent, preserveScaling).toDart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -848,4 +852,156 @@ class ThermionViewerJS implements ThermionViewer {
|
|||||||
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) {
|
Future setSoftShadowOptions(double penumbraScale, double penumbraRatioScale) {
|
||||||
return _shim.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toDart;
|
return _shim.setSoftShadowOptions(penumbraScale, penumbraRatioScale).toDart;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Uint8List> capture() async {
|
||||||
|
final captured = await _shim.capture().toDart;
|
||||||
|
return captured.toDart;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
late (double, double) viewportDimensions;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Aabb2> getBoundingBox(ThermionEntity entity) {
|
||||||
|
// return _shim.getBoundingBox(entity);
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCameraFov(bool horizontal) {
|
||||||
|
// TODO: implement getCameraFov
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queueRelativePositionUpdateWorldAxis(ThermionEntity entity,
|
||||||
|
double viewportX, double viewportY, double x, double y, double z) {
|
||||||
|
// TODO: implement queueRelativePositionUpdateWorldAxis
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
double pixelRatio;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future createIbl(double r, double g, double b, double intensity) {
|
||||||
|
// TODO: implement createIbl
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement gizmoPickResult
|
||||||
|
Stream<FilamentPickResult> get gizmoPickResult => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void pickGizmo(int x, int y) {
|
||||||
|
// TODO: implement pickGizmo
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setGizmoVisibility(bool visible) {
|
||||||
|
// TODO: implement setGizmoVisibility
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLayerEnabled(int layer, bool enabled) {
|
||||||
|
// TODO: implement setLayerEnabled
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement entitiesAdded
|
||||||
|
Stream<ThermionEntity> get entitiesAdded => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement entitiesRemoved
|
||||||
|
Stream<ThermionEntity> get entitiesRemoved => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity?> getAncestor(ThermionEntity entity) {
|
||||||
|
// TODO: implement getAncestor
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCameraNear() {
|
||||||
|
// TODO: implement getCameraNear
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<Aabb2> getViewportBoundingBox(ThermionEntity entity) {
|
||||||
|
// TODO: implement getViewportBoundingBox
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement lightsAdded
|
||||||
|
Stream<ThermionEntity> get lightsAdded => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement lightsRemoved
|
||||||
|
Stream<ThermionEntity> get lightsRemoved => throw UnimplementedError();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false}) {
|
||||||
|
// TODO: implement loadGlbFromBuffer
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future queuePositionUpdateFromViewportCoords(ThermionEntity entity, double x, double y) {
|
||||||
|
// TODO: implement queuePositionUpdateFromViewportCoords
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future removeStencilHighlight(ThermionEntity entity) {
|
||||||
|
// TODO: implement removeStencilHighlight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraLensProjection(double near, double far, double aspect, double focalLength) {
|
||||||
|
// TODO: implement setCameraLensProjection
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setCameraModelMatrix4(Matrix4 matrix) {
|
||||||
|
// TODO: implement setCameraModelMatrix4
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLightDirection(ThermionEntity lightEntity, Vector3 direction) {
|
||||||
|
// TODO: implement setLightDirection
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setLightPosition(ThermionEntity lightEntity, double x, double y, double z) {
|
||||||
|
// TODO: implement setLightPosition
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialPropertyFloat(ThermionEntity entity, String propertyName, int materialIndex, double value) {
|
||||||
|
// TODO: implement setMaterialPropertyFloat
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setMaterialPropertyFloat4(ThermionEntity entity, String propertyName, int materialIndex, double f1, double f2, double f3, double f4) {
|
||||||
|
// TODO: implement setMaterialPropertyFloat4
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future setStencilHighlight(ThermionEntity entity, {double r = 1.0, double g = 0.0, double b = 0.0}) {
|
||||||
|
// TODO: implement setStencilHighlight
|
||||||
|
throw UnimplementedError();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,6 +22,9 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
|||||||
@JS('render')
|
@JS('render')
|
||||||
external JSPromise render();
|
external JSPromise render();
|
||||||
|
|
||||||
|
@JS('capture')
|
||||||
|
external JSPromise<JSUint8Array> capture();
|
||||||
|
|
||||||
@JS('setFrameRate')
|
@JS('setFrameRate')
|
||||||
external JSPromise setFrameRate(int framerate);
|
external JSPromise setFrameRate(int framerate);
|
||||||
|
|
||||||
@@ -184,6 +187,7 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
|||||||
bool reverse,
|
bool reverse,
|
||||||
bool replaceActive,
|
bool replaceActive,
|
||||||
double crossfade,
|
double crossfade,
|
||||||
|
double startOffset,
|
||||||
);
|
);
|
||||||
|
|
||||||
@JS('playAnimationByName')
|
@JS('playAnimationByName')
|
||||||
@@ -216,7 +220,7 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
|||||||
external JSPromise<JSNumber> getMainCamera();
|
external JSPromise<JSNumber> getMainCamera();
|
||||||
|
|
||||||
@JS('setCameraFov')
|
@JS('setCameraFov')
|
||||||
external JSPromise setCameraFov(double degrees, double width, double height);
|
external JSPromise setCameraFov(double degrees, bool horizontal);
|
||||||
|
|
||||||
@JS('setToneMapping')
|
@JS('setToneMapping')
|
||||||
external JSPromise setToneMapping(int mapper);
|
external JSPromise setToneMapping(int mapper);
|
||||||
@@ -374,7 +378,7 @@ extension type ThermionViewerJSShim(JSObject _) implements JSObject {
|
|||||||
JSArray<JSNumber> indices, String? materialPath, int primitiveType);
|
JSArray<JSNumber> indices, String? materialPath, int primitiveType);
|
||||||
|
|
||||||
@JS('setParent')
|
@JS('setParent')
|
||||||
external JSPromise setParent(ThermionEntity child, ThermionEntity parent);
|
external JSPromise setParent(ThermionEntity child, ThermionEntity parent, bool preserveScaling);
|
||||||
|
|
||||||
@JS('getParent')
|
@JS('getParent')
|
||||||
external JSPromise<JSNumber> getParent(ThermionEntity child);
|
external JSPromise<JSNumber> getParent(ThermionEntity child);
|
||||||
File diff suppressed because it is too large
Load Diff
104
thermion_dart/native/include/APIBoundaryTypes.h
Normal file
104
thermion_dart/native/include/APIBoundaryTypes.h
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef int32_t EntityId;
|
||||||
|
typedef int32_t _ManipulatorMode;
|
||||||
|
typedef struct TCamera TCamera;
|
||||||
|
typedef struct TMaterialInstance TMaterialInstance;
|
||||||
|
typedef struct TEngine TEngine;
|
||||||
|
typedef struct TViewer TViewer;
|
||||||
|
|
||||||
|
struct TMaterialKey {
|
||||||
|
bool doubleSided = 1;
|
||||||
|
bool unlit = 1;
|
||||||
|
bool hasVertexColors = 1;
|
||||||
|
bool hasBaseColorTexture = 1;
|
||||||
|
bool hasNormalTexture = 1;
|
||||||
|
bool hasOcclusionTexture = 1;
|
||||||
|
bool hasEmissiveTexture = 1;
|
||||||
|
bool useSpecularGlossiness = 1;
|
||||||
|
int alphaMode = 4;
|
||||||
|
bool enableDiagnostics = 4;
|
||||||
|
union {
|
||||||
|
#ifdef __cplusplus
|
||||||
|
struct {
|
||||||
|
bool hasMetallicRoughnessTexture;
|
||||||
|
uint8_t metallicRoughnessUV;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
bool hasSpecularGlossinessTexture;
|
||||||
|
uint8_t specularGlossinessUV;
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
struct {
|
||||||
|
bool hasMetallicRoughnessTexture = 1;
|
||||||
|
uint8_t metallicRoughnessUV = 7;
|
||||||
|
};
|
||||||
|
struct {
|
||||||
|
bool hasSpecularGlossinessTexture = 1;
|
||||||
|
uint8_t specularGlossinessUV = 7;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
uint8_t baseColorUV;
|
||||||
|
// -- 32 bit boundary --
|
||||||
|
bool hasClearCoatTexture = 1;
|
||||||
|
uint8_t clearCoatUV = 7;
|
||||||
|
bool hasClearCoatRoughnessTexture = 1;
|
||||||
|
uint8_t clearCoatRoughnessUV = 7;
|
||||||
|
bool hasClearCoatNormalTexture = 1;
|
||||||
|
uint8_t clearCoatNormalUV = 7;
|
||||||
|
bool hasClearCoat = 1;
|
||||||
|
bool hasTransmission = 1;
|
||||||
|
bool hasTextureTransforms = 6;
|
||||||
|
// -- 32 bit boundary --
|
||||||
|
uint8_t emissiveUV;
|
||||||
|
uint8_t aoUV;
|
||||||
|
uint8_t normalUV;
|
||||||
|
bool hasTransmissionTexture = 1;
|
||||||
|
uint8_t transmissionUV = 7;
|
||||||
|
// -- 32 bit boundary --
|
||||||
|
bool hasSheenColorTexture = 1;
|
||||||
|
uint8_t sheenColorUV = 7;
|
||||||
|
bool hasSheenRoughnessTexture = 1;
|
||||||
|
uint8_t sheenRoughnessUV = 7;
|
||||||
|
bool hasVolumeThicknessTexture = 1;
|
||||||
|
uint8_t volumeThicknessUV = 7;
|
||||||
|
bool hasSheen = 1;
|
||||||
|
bool hasIOR = 1;
|
||||||
|
bool hasVolume = 1;
|
||||||
|
} ;
|
||||||
|
typedef struct TMaterialKey TMaterialKey;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double x;
|
||||||
|
double y;
|
||||||
|
double z;
|
||||||
|
double w;
|
||||||
|
} double4;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double col1[4];
|
||||||
|
double col2[4];
|
||||||
|
double col3[4];
|
||||||
|
double col4[4];
|
||||||
|
} double4x4;
|
||||||
|
|
||||||
|
struct Aabb2 {
|
||||||
|
float minX;
|
||||||
|
float minY;
|
||||||
|
float maxX;
|
||||||
|
float maxY;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Aabb2 Aabb2;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
59
thermion_dart/native/include/CustomGeometry.hpp
Normal file
59
thermion_dart/native/include/CustomGeometry.hpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/VertexBuffer.h>
|
||||||
|
#include <filament/IndexBuffer.h>
|
||||||
|
#include <filament/TransformManager.h>
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/Viewport.h>
|
||||||
|
#include <filament/Frustum.h>
|
||||||
|
|
||||||
|
namespace thermion_filament
|
||||||
|
{
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
|
||||||
|
// CustomGeometry.h
|
||||||
|
class CustomGeometry {
|
||||||
|
public:
|
||||||
|
CustomGeometry(
|
||||||
|
float* vertices,
|
||||||
|
uint32_t numVertices,
|
||||||
|
float* normals,
|
||||||
|
uint32_t numNormals,
|
||||||
|
float *uvs,
|
||||||
|
uint32_t numUvs,
|
||||||
|
uint16_t* indices,
|
||||||
|
uint32_t numIndices,
|
||||||
|
RenderableManager::PrimitiveType primitiveType,
|
||||||
|
Engine* engine);
|
||||||
|
~CustomGeometry();
|
||||||
|
|
||||||
|
VertexBuffer* vertexBuffer() const;
|
||||||
|
IndexBuffer* indexBuffer() const;
|
||||||
|
Box getBoundingBox() const;
|
||||||
|
|
||||||
|
float* vertices = nullptr;
|
||||||
|
float* normals = nullptr;
|
||||||
|
float *uvs = nullptr;
|
||||||
|
uint32_t numVertices = 0;
|
||||||
|
uint16_t* indices = 0;
|
||||||
|
uint32_t numIndices = 0;
|
||||||
|
Box boundingBox;
|
||||||
|
RenderableManager::PrimitiveType primitiveType;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Engine* _engine;
|
||||||
|
bool _vertexBufferFreed = false;
|
||||||
|
bool _indexBufferFreed = false;
|
||||||
|
|
||||||
|
void computeBoundingBox();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -42,8 +42,6 @@ namespace thermion_filament
|
|||||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
||||||
|
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
using namespace filament;
|
|
||||||
using namespace filament::math;
|
|
||||||
using namespace gltfio;
|
using namespace gltfio;
|
||||||
using namespace camutils;
|
using namespace camutils;
|
||||||
|
|
||||||
@@ -71,12 +69,13 @@ namespace thermion_filament
|
|||||||
void loadIbl(const char *const iblUri, float intensity);
|
void loadIbl(const char *const iblUri, float intensity);
|
||||||
void removeIbl();
|
void removeIbl();
|
||||||
void rotateIbl(const math::mat3f &matrix);
|
void rotateIbl(const math::mat3f &matrix);
|
||||||
|
void createIbl(float r, float g, float b, float intensity);
|
||||||
|
|
||||||
void removeEntity(EntityId asset);
|
void removeEntity(EntityId asset);
|
||||||
void clearEntities();
|
void clearEntities();
|
||||||
|
|
||||||
void updateViewportAndCameraProjection(int height, int width, float scaleFactor);
|
void updateViewport(uint32_t width, uint32_t height);
|
||||||
void render(
|
bool render(
|
||||||
uint64_t frameTimeInNanos,
|
uint64_t frameTimeInNanos,
|
||||||
void *pixelBuffer,
|
void *pixelBuffer,
|
||||||
void (*callback)(void *buf, size_t size, void *data),
|
void (*callback)(void *buf, size_t size, void *data),
|
||||||
@@ -86,7 +85,10 @@ namespace thermion_filament
|
|||||||
bool setCamera(EntityId asset, const char *nodeName);
|
bool setCamera(EntityId asset, const char *nodeName);
|
||||||
void setMainCamera();
|
void setMainCamera();
|
||||||
EntityId getMainCamera();
|
EntityId getMainCamera();
|
||||||
void setCameraFov(double fovDegrees, double aspect);
|
Camera* getCamera(EntityId entity);
|
||||||
|
|
||||||
|
float getCameraFov(bool horizontal);
|
||||||
|
void setCameraFov(double fovDegrees, bool horizontal);
|
||||||
|
|
||||||
void createSwapChain(const void *surface, uint32_t width, uint32_t height);
|
void createSwapChain(const void *surface, uint32_t width, uint32_t height);
|
||||||
void destroySwapChain();
|
void destroySwapChain();
|
||||||
@@ -100,24 +102,8 @@ namespace thermion_filament
|
|||||||
void clearBackgroundImage();
|
void clearBackgroundImage();
|
||||||
void setBackgroundImagePosition(float x, float y, bool clamp);
|
void setBackgroundImagePosition(float x, float y, bool clamp);
|
||||||
|
|
||||||
// Camera methods
|
|
||||||
void moveCameraToAsset(EntityId entityId);
|
|
||||||
void setViewFrustumCulling(bool enabled);
|
void setViewFrustumCulling(bool enabled);
|
||||||
void setCameraExposure(float aperture, float shutterSpeed, float sensitivity);
|
|
||||||
void setCameraPosition(float x, float y, float z);
|
|
||||||
void setCameraRotation(float w, float x, float y, float z);
|
|
||||||
const math::mat4 getCameraModelMatrix();
|
|
||||||
const math::mat4 getCameraViewMatrix();
|
|
||||||
const math::mat4 getCameraProjectionMatrix();
|
|
||||||
const math::mat4 getCameraCullingProjectionMatrix();
|
|
||||||
const filament::Frustum getCameraFrustum();
|
|
||||||
void setCameraModelMatrix(const float *const matrix);
|
|
||||||
void setCameraProjectionMatrix(const double *const matrix, double near, double far);
|
|
||||||
void setCameraFocalLength(float focalLength);
|
|
||||||
void setCameraCulling(double near, double far);
|
|
||||||
double getCameraCullingNear();
|
|
||||||
double getCameraCullingFar();
|
|
||||||
void setCameraFocusDistance(float focusDistance);
|
|
||||||
void setCameraManipulatorOptions(filament::camutils::Mode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
void setCameraManipulatorOptions(filament::camutils::Mode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||||
void grabBegin(float x, float y, bool pan);
|
void grabBegin(float x, float y, bool pan);
|
||||||
void grabUpdate(float x, float y);
|
void grabUpdate(float x, float y);
|
||||||
@@ -126,6 +112,9 @@ namespace thermion_filament
|
|||||||
void scrollUpdate(float x, float y, float delta);
|
void scrollUpdate(float x, float y, float delta);
|
||||||
void scrollEnd();
|
void scrollEnd();
|
||||||
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
||||||
|
Engine* getEngine() {
|
||||||
|
return _engine;
|
||||||
|
}
|
||||||
|
|
||||||
EntityId addLight(
|
EntityId addLight(
|
||||||
LightManager::Type t,
|
LightManager::Type t,
|
||||||
@@ -144,12 +133,15 @@ namespace thermion_filament
|
|||||||
float sunHaloSize,
|
float sunHaloSize,
|
||||||
float sunHaloFallof,
|
float sunHaloFallof,
|
||||||
bool shadows);
|
bool shadows);
|
||||||
|
void setLightPosition(EntityId entityId, float x, float y, float z);
|
||||||
|
void setLightDirection(EntityId entityId, float x, float y, float z);
|
||||||
void removeLight(EntityId entityId);
|
void removeLight(EntityId entityId);
|
||||||
void clearLights();
|
void clearLights();
|
||||||
void setPostProcessing(bool enabled);
|
void setPostProcessing(bool enabled);
|
||||||
|
|
||||||
void setRecording(bool recording);
|
void setRecording(bool recording);
|
||||||
void setRecordingOutputDirectory(const char *path);
|
void setRecordingOutputDirectory(const char *path);
|
||||||
|
void capture(uint8_t *out, bool useFence, void (*onComplete)());
|
||||||
|
|
||||||
void setAntiAliasing(bool msaaEnabled, bool fxaaEnabled, bool taaEnabled);
|
void setAntiAliasing(bool msaaEnabled, bool fxaaEnabled, bool taaEnabled);
|
||||||
void setDepthOfField();
|
void setDepthOfField();
|
||||||
@@ -157,18 +149,20 @@ namespace thermion_filament
|
|||||||
void setShadowType(ShadowType shadowType);
|
void setShadowType(ShadowType shadowType);
|
||||||
void setSoftShadowOptions( float penumbraScale, float penumbraRatioScale);
|
void setSoftShadowOptions( float penumbraScale, float penumbraRatioScale);
|
||||||
|
|
||||||
EntityId createGeometry(float *vertices, uint32_t numVertices, uint16_t *indices, uint32_t numIndices, filament::RenderableManager::PrimitiveType primitiveType = RenderableManager::PrimitiveType::TRIANGLES, const char *materialPath = nullptr);
|
|
||||||
|
|
||||||
SceneManager *const getSceneManager()
|
SceneManager *const getSceneManager()
|
||||||
{
|
{
|
||||||
return (SceneManager *const)_sceneManager;
|
return (SceneManager *const)_sceneManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void unprojectTexture(EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||||
void* _context = nullptr;
|
void* _context = nullptr;
|
||||||
Scene *_scene = nullptr;
|
Scene *_scene = nullptr;
|
||||||
|
|
||||||
View *_view = nullptr;
|
View *_view = nullptr;
|
||||||
|
|
||||||
Engine *_engine = nullptr;
|
Engine *_engine = nullptr;
|
||||||
thermion_filament::ThreadPool *_tp = nullptr;
|
thermion_filament::ThreadPool *_tp = nullptr;
|
||||||
Renderer *_renderer = nullptr;
|
Renderer *_renderer = nullptr;
|
||||||
@@ -187,32 +181,26 @@ namespace thermion_filament
|
|||||||
Skybox *_skybox = nullptr;
|
Skybox *_skybox = nullptr;
|
||||||
Texture *_iblTexture = nullptr;
|
Texture *_iblTexture = nullptr;
|
||||||
IndirectLight *_indirectLight = nullptr;
|
IndirectLight *_indirectLight = nullptr;
|
||||||
bool _recomputeAabb = false;
|
|
||||||
bool _actualSize = false;
|
|
||||||
|
|
||||||
float _frameInterval = 1000.0 / 60.0;
|
float _frameInterval = 1000.0 / 60.0;
|
||||||
|
|
||||||
// Camera properties
|
// Camera properties
|
||||||
Camera *_mainCamera = nullptr; // the default camera added to every scene. If you want the *active* camera, access via View.
|
Camera *_mainCamera = nullptr; // the default camera added to every scene. If you want the *active* camera, access via View.
|
||||||
float _cameraFocalLength = 28.0f;
|
|
||||||
float _cameraFocusDistance = 0.0f;
|
|
||||||
Manipulator<double> *_manipulator = nullptr;
|
Manipulator<double> *_manipulator = nullptr;
|
||||||
filament::camutils::Mode _manipulatorMode = filament::camutils::Mode::ORBIT;
|
filament::camutils::Mode _manipulatorMode = filament::camutils::Mode::ORBIT;
|
||||||
double _orbitSpeedX = 0.01;
|
double _orbitSpeedX = 0.01;
|
||||||
double _orbitSpeedY = 0.01;
|
double _orbitSpeedY = 0.01;
|
||||||
double _zoomSpeed = 0.01;
|
double _zoomSpeed = 0.01;
|
||||||
math::mat4f _cameraPosition;
|
|
||||||
math::mat4f _cameraRotation;
|
|
||||||
void _createManipulator();
|
void _createManipulator();
|
||||||
double _near = 0.05;
|
|
||||||
double _far = 1000.0;
|
|
||||||
|
|
||||||
ColorGrading *colorGrading = nullptr;
|
ColorGrading *colorGrading = nullptr;
|
||||||
|
|
||||||
// background image properties
|
// background image properties
|
||||||
uint32_t _imageHeight = 0;
|
uint32_t _imageHeight = 0;
|
||||||
uint32_t _imageWidth = 0;
|
uint32_t _imageWidth = 0;
|
||||||
mat4f _imageScale;
|
filament::math::mat4f _imageScale;
|
||||||
Texture *_imageTexture = nullptr;
|
Texture *_imageTexture = nullptr;
|
||||||
Texture *_dummyImageTexture = nullptr;
|
Texture *_dummyImageTexture = nullptr;
|
||||||
utils::Entity _imageEntity;
|
utils::Entity _imageEntity;
|
||||||
|
|||||||
113
thermion_dart/native/include/Gizmo.hpp
Normal file
113
thermion_dart/native/include/Gizmo.hpp
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utils/Entity.h>
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/Material.h>
|
||||||
|
#include <filament/MaterialInstance.h>
|
||||||
|
#include <filament/Scene.h>
|
||||||
|
#include <filament/Camera.h>
|
||||||
|
#include <filament/View.h>
|
||||||
|
#include <filament/Viewport.h>
|
||||||
|
|
||||||
|
#include <gltfio/AssetLoader.h>
|
||||||
|
#include <gltfio/FilamentAsset.h>
|
||||||
|
#include <gltfio/FilamentInstance.h>
|
||||||
|
#include <gltfio/ResourceLoader.h>
|
||||||
|
|
||||||
|
#include <filament/IndexBuffer.h>
|
||||||
|
#include <filament/InstanceBuffer.h>
|
||||||
|
|
||||||
|
#include "material/gizmo.h"
|
||||||
|
|
||||||
|
#include "ThermionDartApi.h"
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
using namespace utils;
|
||||||
|
|
||||||
|
class Gizmo {
|
||||||
|
|
||||||
|
enum Axis { X, Y, Z};
|
||||||
|
|
||||||
|
class PickCallbackHandler {
|
||||||
|
public:
|
||||||
|
PickCallbackHandler(Gizmo* gizmo, void (*callback)(EntityId entityId, int x, int y)) : _gizmo(gizmo), _callback(callback) {};
|
||||||
|
void handle(filament::View::PickingQueryResult const &result) {
|
||||||
|
auto x = static_cast<int32_t>(result.fragCoords.x);
|
||||||
|
auto y= static_cast<int32_t>(result.fragCoords.y);
|
||||||
|
for(int i = 0; i < 7; i++) {
|
||||||
|
if(_gizmo->_entities[i] == result.renderable) {
|
||||||
|
if(i < 4) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_gizmo->highlight(_gizmo->_entities[i - 4]);
|
||||||
|
_callback(Entity::smuggle(_gizmo->_entities[i - 4]), x, y);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_gizmo->unhighlight();
|
||||||
|
_callback(0, x, y);
|
||||||
|
delete(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Gizmo* _gizmo;
|
||||||
|
void (*_callback)(EntityId entityId, int x, int y);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
Gizmo(Engine& engine, View *view, Scene *scene);
|
||||||
|
~Gizmo();
|
||||||
|
|
||||||
|
Entity x() {
|
||||||
|
return _entities[0];
|
||||||
|
};
|
||||||
|
Entity y() {
|
||||||
|
return _entities[1];
|
||||||
|
};
|
||||||
|
Entity z() {
|
||||||
|
return _entities[2];
|
||||||
|
};
|
||||||
|
Entity center() {
|
||||||
|
return _entities[3];
|
||||||
|
};
|
||||||
|
View* view() {
|
||||||
|
return _view;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isActive() {
|
||||||
|
return _isActive;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
||||||
|
bool isGizmoEntity(Entity entity);
|
||||||
|
void setVisibility(bool visible);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createTransparentRectangles();
|
||||||
|
void highlight(Entity entity);
|
||||||
|
void unhighlight();
|
||||||
|
Engine &_engine;
|
||||||
|
View *_view;
|
||||||
|
Scene *_scene;
|
||||||
|
filament::Camera *_camera;
|
||||||
|
utils::Entity _entities[7] = { utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity() };
|
||||||
|
Material* _material;
|
||||||
|
MaterialInstance* _materialInstances[7];
|
||||||
|
math::float4 inactiveColors[3] {
|
||||||
|
math::float4 { 1.0f, 0.0f, 0.0f, 0.5f },
|
||||||
|
math::float4 { 0.0f, 1.0f, 0.0f, 0.5f },
|
||||||
|
math::float4 { 0.0f, 0.0f, 1.0f, 0.5f },
|
||||||
|
};
|
||||||
|
math::float4 activeColors[3] {
|
||||||
|
math::float4 { 1.0f, 0.0f, 0.0f, 1.0f },
|
||||||
|
math::float4 { 0.0f, 1.0f, 0.0f, 1.0f },
|
||||||
|
math::float4 { 0.0f, 0.0f, 1.0f, 1.0f },
|
||||||
|
};
|
||||||
|
bool _isActive = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
52
thermion_dart/native/include/GridOverlay.hpp
Normal file
52
thermion_dart/native/include/GridOverlay.hpp
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <utils/Entity.h>
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/Material.h>
|
||||||
|
#include <filament/MaterialInstance.h>
|
||||||
|
#include <filament/Scene.h>
|
||||||
|
#include <filament/Camera.h>
|
||||||
|
#include <filament/View.h>
|
||||||
|
#include <filament/Viewport.h>
|
||||||
|
|
||||||
|
#include <gltfio/AssetLoader.h>
|
||||||
|
#include <gltfio/FilamentAsset.h>
|
||||||
|
#include <gltfio/FilamentInstance.h>
|
||||||
|
#include <gltfio/ResourceLoader.h>
|
||||||
|
|
||||||
|
#include <filament/IndexBuffer.h>
|
||||||
|
#include <filament/InstanceBuffer.h>
|
||||||
|
|
||||||
|
#include "material/gizmo.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
using namespace utils;
|
||||||
|
|
||||||
|
class GridOverlay {
|
||||||
|
public:
|
||||||
|
GridOverlay(Engine& engine);
|
||||||
|
void destroy();
|
||||||
|
|
||||||
|
utils::Entity sphere() {
|
||||||
|
return _sphereEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::Entity grid() {
|
||||||
|
return _gridEntity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Engine &_engine;
|
||||||
|
utils::Entity _gridEntity;
|
||||||
|
utils::Entity _sphereEntity;
|
||||||
|
Material* _material;
|
||||||
|
MaterialInstance* _materialInstance;
|
||||||
|
MaterialInstance* _sphereMaterialInstance;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -4,8 +4,11 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include <filament/Scene.h>
|
#include <filament/Scene.h>
|
||||||
|
#include <filament/Camera.h>
|
||||||
|
#include <filament/View.h>
|
||||||
|
|
||||||
#include <gltfio/AssetLoader.h>
|
#include <gltfio/AssetLoader.h>
|
||||||
#include <gltfio/FilamentAsset.h>
|
#include <gltfio/FilamentAsset.h>
|
||||||
@@ -14,15 +17,21 @@
|
|||||||
|
|
||||||
#include <filament/IndexBuffer.h>
|
#include <filament/IndexBuffer.h>
|
||||||
#include <filament/InstanceBuffer.h>
|
#include <filament/InstanceBuffer.h>
|
||||||
|
#include <utils/NameComponentManager.h>
|
||||||
|
|
||||||
#include "material/gizmo.h"
|
#include "material/gizmo.h"
|
||||||
#include "utils/NameComponentManager.h"
|
|
||||||
|
#include "CustomGeometry.hpp"
|
||||||
|
#include "Gizmo.hpp"
|
||||||
|
#include "APIBoundaryTypes.h"
|
||||||
|
#include "GridOverlay.hpp"
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.hpp"
|
||||||
#include "components/CollisionComponentManager.hpp"
|
#include "components/CollisionComponentManager.hpp"
|
||||||
#include "components/AnimationComponentManager.hpp"
|
#include "components/AnimationComponentManager.hpp"
|
||||||
|
|
||||||
#include "tsl/robin_map.h"
|
#include "tsl/robin_map.h"
|
||||||
|
|
||||||
|
|
||||||
namespace thermion_filament
|
namespace thermion_filament
|
||||||
{
|
{
|
||||||
typedef int32_t EntityId;
|
typedef int32_t EntityId;
|
||||||
@@ -37,13 +46,45 @@ namespace thermion_filament
|
|||||||
class SceneManager
|
class SceneManager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SceneManager(const ResourceLoaderWrapperImpl *const loader,
|
SceneManager(View* view,
|
||||||
|
const ResourceLoaderWrapperImpl *const loader,
|
||||||
Engine *engine,
|
Engine *engine,
|
||||||
Scene *scene,
|
Scene *scene,
|
||||||
const char *uberArchivePath);
|
const char *uberArchivePath);
|
||||||
~SceneManager();
|
~SceneManager();
|
||||||
|
|
||||||
EntityId loadGltf(const char *uri, const char *relativeResourcePath);
|
enum LAYERS {
|
||||||
|
DEFAULT_ASSETS = 0,
|
||||||
|
BACKGROUND = 6,
|
||||||
|
OVERLAY = 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
class HighlightOverlay {
|
||||||
|
public:
|
||||||
|
HighlightOverlay(EntityId id, SceneManager* const sceneManager, Engine* const engine, float r, float g, float b);
|
||||||
|
~HighlightOverlay();
|
||||||
|
|
||||||
|
bool isValid() {
|
||||||
|
return !_entity.isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
MaterialInstance* _highlightMaterialInstance = nullptr;
|
||||||
|
bool _isGeometryEntity = false;
|
||||||
|
bool _isGltfAsset = false;
|
||||||
|
FilamentInstance* _newInstance = nullptr;
|
||||||
|
Entity _entity;
|
||||||
|
Engine* const _engine;
|
||||||
|
SceneManager* const _sceneManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
////
|
||||||
|
/// @brief Load the glTF file from the specified path and adds all entities to the scene.
|
||||||
|
/// @param uri the path to the asset. Should be either asset:// (representing a Flutter asset), or file:// (representing a filesystem file).
|
||||||
|
/// @param relativeResourcePath the (relative) path to the asset's resources.
|
||||||
|
/// @return the glTF entity.
|
||||||
|
///
|
||||||
|
EntityId loadGltf(const char *uri, const char *relativeResourcePath, bool keepData = false);
|
||||||
|
|
||||||
////
|
////
|
||||||
/// @brief Load the GLB from the specified path, optionally creating multiple instances.
|
/// @brief Load the GLB from the specified path, optionally creating multiple instances.
|
||||||
@@ -51,8 +92,8 @@ namespace thermion_filament
|
|||||||
/// @param numInstances the number of instances to create.
|
/// @param numInstances the number of instances to create.
|
||||||
/// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset.
|
/// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset.
|
||||||
///
|
///
|
||||||
EntityId loadGlb(const char *uri, int numInstances);
|
EntityId loadGlb(const char *uri, int numInstances, bool keepData);
|
||||||
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1);
|
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0);
|
||||||
EntityId createInstance(EntityId entityId);
|
EntityId createInstance(EntityId entityId);
|
||||||
|
|
||||||
void remove(EntityId entity);
|
void remove(EntityId entity);
|
||||||
@@ -69,6 +110,8 @@ namespace thermion_filament
|
|||||||
void setRotation(EntityId e, float rads, float x, float y, float z, float w);
|
void setRotation(EntityId e, float rads, float x, float y, float z, float w);
|
||||||
void queuePositionUpdate(EntityId e, float x, float y, float z, bool relative);
|
void queuePositionUpdate(EntityId e, float x, float y, float z, bool relative);
|
||||||
void queueRotationUpdate(EntityId e, float rads, float x, float y, float z, float w, bool relative);
|
void queueRotationUpdate(EntityId e, float rads, float x, float y, float z, float w, bool relative);
|
||||||
|
void queueRelativePositionUpdateWorldAxis(EntityId entity, float viewportCoordX, float viewportCoordY, float x, float y, float z);
|
||||||
|
void queueRelativePositionUpdateFromViewportVector(EntityId entityId, float viewportCoordX, float viewportCoordY);
|
||||||
const utils::Entity *getCameraEntities(EntityId e);
|
const utils::Entity *getCameraEntities(EntityId e);
|
||||||
size_t getCameraEntityCount(EntityId e);
|
size_t getCameraEntityCount(EntityId e);
|
||||||
const utils::Entity *getLightEntities(EntityId e) noexcept;
|
const utils::Entity *getLightEntities(EntityId e) noexcept;
|
||||||
@@ -129,10 +172,14 @@ namespace thermion_filament
|
|||||||
void resetBones(EntityId entityId);
|
void resetBones(EntityId entityId);
|
||||||
bool setTransform(EntityId entityId, math::mat4f transform);
|
bool setTransform(EntityId entityId, math::mat4f transform);
|
||||||
bool updateBoneMatrices(EntityId entityId);
|
bool updateBoneMatrices(EntityId entityId);
|
||||||
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f);
|
void playAnimation(EntityId e, int index, bool loop, bool reverse, bool replaceActive, float crossfade = 0.3f, float startOffset = 0.0f);
|
||||||
void stopAnimation(EntityId e, int index);
|
void stopAnimation(EntityId e, int index);
|
||||||
void setMorphTargetWeights(const char *const entityName, float *weights, int count);
|
void setMorphTargetWeights(const char *const entityName, float *weights, int count);
|
||||||
void loadTexture(EntityId entity, const char *resourcePath, int renderableIndex);
|
|
||||||
|
Texture* createTexture(const uint8_t* data, size_t length, const char* name);
|
||||||
|
bool applyTexture(EntityId entityId, Texture *texture, const char* slotName, int materialIndex);
|
||||||
|
void destroyTexture(Texture* texture);
|
||||||
|
|
||||||
void setAnimationFrame(EntityId entity, int animationIndex, int animationFrame);
|
void setAnimationFrame(EntityId entity, int animationIndex, int animationFrame);
|
||||||
bool hide(EntityId entity, const char *meshName);
|
bool hide(EntityId entity, const char *meshName);
|
||||||
bool reveal(EntityId entity, const char *meshName);
|
bool reveal(EntityId entity, const char *meshName);
|
||||||
@@ -146,10 +193,21 @@ namespace thermion_filament
|
|||||||
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
void addCollisionComponent(EntityId entity, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
||||||
void removeCollisionComponent(EntityId entityId);
|
void removeCollisionComponent(EntityId entityId);
|
||||||
EntityId getParent(EntityId child);
|
EntityId getParent(EntityId child);
|
||||||
void setParent(EntityId child, EntityId parent);
|
EntityId getAncestor(EntityId child);
|
||||||
|
void setParent(EntityId child, EntityId parent, bool preserveScaling);
|
||||||
bool addAnimationComponent(EntityId entity);
|
bool addAnimationComponent(EntityId entity);
|
||||||
void removeAnimationComponent(EntityId entity);
|
void removeAnimationComponent(EntityId entity);
|
||||||
|
|
||||||
|
/// @brief renders an outline around the specified entity.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
void setStencilHighlight(EntityId entity, float r, float g, float b);
|
||||||
|
|
||||||
|
/// @brief removes the outline around the specified entity.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
void removeStencilHighlight(EntityId entity);
|
||||||
|
|
||||||
/// @brief returns the number of instances of the FilamentAsset represented by the given entity.
|
/// @brief returns the number of instances of the FilamentAsset represented by the given entity.
|
||||||
/// @param entityId
|
/// @param entityId
|
||||||
/// @return the number of instances
|
/// @return the number of instances
|
||||||
@@ -164,24 +222,97 @@ namespace thermion_filament
|
|||||||
///
|
///
|
||||||
void setPriority(EntityId entity, int priority);
|
void setPriority(EntityId entity, int priority);
|
||||||
|
|
||||||
/// @brief returns the gizmo entity, used to manipulate the global transform for entities
|
/// @brief returns the 2D min/max viewport coordinates of the bounding box for the specified enitty;
|
||||||
/// @param out a pointer to an array of three EntityId {x, y, z}
|
/// @param out a pointer large enough to store four floats (the min/max coordinates of the bounding box)
|
||||||
/// @return
|
/// @return
|
||||||
///
|
///
|
||||||
void getGizmo(EntityId *out);
|
Aabb2 getBoundingBox(EntityId entity);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Toggles the visibility of the given layer.
|
||||||
|
///
|
||||||
|
void setLayerVisibility(SceneManager::LAYERS layer, bool enabled);
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Creates an entity with the specified geometry/material/normals and adds to the scene.
|
||||||
|
/// If [keepData] is true, stores
|
||||||
|
///
|
||||||
|
EntityId createGeometry(
|
||||||
|
float *vertices,
|
||||||
|
uint32_t numVertices,
|
||||||
|
float *normals,
|
||||||
|
uint32_t numNormals,
|
||||||
|
float *uvs,
|
||||||
|
uint32_t numUvs,
|
||||||
|
uint16_t *indices,
|
||||||
|
uint32_t numIndices,
|
||||||
|
filament::RenderableManager::PrimitiveType primitiveType = RenderableManager::PrimitiveType::TRIANGLES,
|
||||||
|
MaterialInstance* materialInstance = nullptr,
|
||||||
|
bool keepData = false
|
||||||
|
);
|
||||||
|
|
||||||
friend class FilamentViewer;
|
friend class FilamentViewer;
|
||||||
|
|
||||||
|
Gizmo* gizmo = nullptr;
|
||||||
|
|
||||||
|
gltfio::MaterialProvider * const unlitMaterialProvider() {
|
||||||
|
return _unlitMaterialProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isGeometryEntity(EntityId entity) {
|
||||||
|
return _geometry.find(entity) != _geometry.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CustomGeometry* const getGeometry(EntityId entityId) {
|
||||||
|
return _geometry[entityId].get();
|
||||||
|
}
|
||||||
|
|
||||||
|
Scene* const getScene() {
|
||||||
|
return _scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isGltfAsset(EntityId entity) {
|
||||||
|
return getAssetByEntityId(entity) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
gltfio::FilamentInstance *getInstanceByEntityId(EntityId entityId);
|
||||||
|
gltfio::FilamentAsset *getAssetByEntityId(EntityId entityId);
|
||||||
|
|
||||||
|
gltfio::FilamentInstance *createGltfAssetInstance(FilamentAsset* asset) {
|
||||||
|
return _assetLoader->createInstance(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialInstance* getMaterialInstanceAt(EntityId entityId, int materialIndex);
|
||||||
|
|
||||||
|
void setMaterialProperty(EntityId entity, int materialIndex, const char* property, float value);
|
||||||
|
void setMaterialProperty(EntityId entity, int materialIndex, const char* property, int32_t value);
|
||||||
|
void setMaterialProperty(EntityId entityId, int materialIndex, const char* property, filament::math::float4& value);
|
||||||
|
|
||||||
|
MaterialInstance* createUbershaderMaterialInstance(MaterialKey key);
|
||||||
|
void destroy(MaterialInstance* materialInstance);
|
||||||
|
|
||||||
|
gltfio::MaterialProvider* getUbershaderProvider() {
|
||||||
|
return _ubershaderProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
MaterialInstance* createUnlitMaterialInstance();
|
||||||
|
|
||||||
|
void setVisibilityLayer(EntityId entityId, int layer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
gltfio::AssetLoader *_assetLoader = nullptr;
|
gltfio::AssetLoader *_assetLoader = nullptr;
|
||||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||||
Engine *_engine;
|
Engine *_engine = nullptr;
|
||||||
Scene *_scene;
|
Scene *_scene = nullptr;
|
||||||
|
View* _view = nullptr;
|
||||||
|
|
||||||
gltfio::MaterialProvider *_ubershaderProvider = nullptr;
|
gltfio::MaterialProvider *_ubershaderProvider = nullptr;
|
||||||
|
gltfio::MaterialProvider *_unlitMaterialProvider = nullptr;
|
||||||
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
|
gltfio::ResourceLoader *_gltfResourceLoader = nullptr;
|
||||||
gltfio::TextureProvider *_stbDecoder = nullptr;
|
gltfio::TextureProvider *_stbDecoder = nullptr;
|
||||||
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
||||||
std::mutex _mutex;
|
std::mutex _mutex;
|
||||||
|
std::mutex _stencilMutex;
|
||||||
|
|
||||||
utils::NameComponentManager *_ncm;
|
utils::NameComponentManager *_ncm;
|
||||||
|
|
||||||
@@ -190,22 +321,20 @@ namespace thermion_filament
|
|||||||
gltfio::FilamentInstance *>
|
gltfio::FilamentInstance *>
|
||||||
_instances;
|
_instances;
|
||||||
tsl::robin_map<EntityId, gltfio::FilamentAsset *> _assets;
|
tsl::robin_map<EntityId, gltfio::FilamentAsset *> _assets;
|
||||||
|
tsl::robin_map<EntityId, unique_ptr<CustomGeometry>> _geometry;
|
||||||
|
tsl::robin_map<EntityId, unique_ptr<HighlightOverlay>> _highlighted;
|
||||||
tsl::robin_map<EntityId, std::tuple<math::float3, bool, math::quatf, bool, float>> _transformUpdates;
|
tsl::robin_map<EntityId, std::tuple<math::float3, bool, math::quatf, bool, float>> _transformUpdates;
|
||||||
|
std::set<Texture*> _textures;
|
||||||
|
|
||||||
AnimationComponentManager *_animationComponentManager = nullptr;
|
AnimationComponentManager *_animationComponentManager = nullptr;
|
||||||
CollisionComponentManager *_collisionComponentManager = nullptr;
|
CollisionComponentManager *_collisionComponentManager = nullptr;
|
||||||
|
|
||||||
gltfio::FilamentInstance *getInstanceByEntityId(EntityId entityId);
|
|
||||||
gltfio::FilamentAsset *getAssetByEntityId(EntityId entityId);
|
|
||||||
|
|
||||||
utils::Entity findEntityByName(
|
utils::Entity findEntityByName(
|
||||||
const gltfio::FilamentInstance *instance,
|
const gltfio::FilamentInstance *instance,
|
||||||
const char *entityName);
|
const char *entityName);
|
||||||
|
|
||||||
EntityId addGizmo();
|
GridOverlay* _gridOverlay = nullptr;
|
||||||
utils::Entity _gizmo[3];
|
|
||||||
Material* _gizmoMaterial;
|
|
||||||
MaterialInstance* _gizmoMaterialInstances[3];
|
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,77 +46,87 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "APIBoundaryTypes.h"
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.hpp"
|
||||||
|
|
||||||
typedef int32_t EntityId;
|
|
||||||
typedef int32_t _ManipulatorMode;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE const void *create_filament_viewer(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
EMSCRIPTEN_KEEPALIVE TViewer *create_filament_viewer(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void *get_scene_manager(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void *get_scene_manager(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void create_render_target(const void *const viewer, intptr_t texture, uint32_t width, uint32_t height);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(const void *const viewer);
|
// Engine
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image(const void *const viewer, const char *path, bool fillHeight);
|
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(const void *const viewer, float x, float y, bool clamp);
|
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_color(const void *const viewer, const float r, const float g, const float b, const float a);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(const void *const viewer, int toneMapping);
|
EMSCRIPTEN_KEEPALIVE void create_render_target(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_bloom(const void *const viewer, float strength);
|
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void load_skybox(const void *const viewer, const char *skyboxPath);
|
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight);
|
||||||
EMSCRIPTEN_KEEPALIVE void load_ibl(const void *const viewer, const char *iblPath, float intensity);
|
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp);
|
||||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(const void *const viewer, float *rotationMatrix);
|
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(TViewer *viewer, int toneMapping);
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_ibl(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void set_bloom(TViewer *viewer, float strength);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_ibl(TViewer *viewer, const char *iblPath, float intensity);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId add_light(
|
EMSCRIPTEN_KEEPALIVE EntityId add_light(
|
||||||
const void *const viewer,
|
TViewer *viewer,
|
||||||
uint8_t type,
|
uint8_t type,
|
||||||
float colour,
|
float colour,
|
||||||
float intensity,
|
float intensity,
|
||||||
float posX,
|
float posX,
|
||||||
float posY,
|
float posY,
|
||||||
float posZ,
|
float posZ,
|
||||||
float dirX,
|
float dirX,
|
||||||
float dirY,
|
float dirY,
|
||||||
float dirZ,
|
float dirZ,
|
||||||
float falloffRadius,
|
float falloffRadius,
|
||||||
float spotLightConeInner,
|
float spotLightConeInner,
|
||||||
float spotLightConeOuter,
|
float spotLightConeOuter,
|
||||||
float sunAngularRadius,
|
float sunAngularRadius,
|
||||||
float sunHaloSize,
|
float sunHaloSize,
|
||||||
float sunHaloFallof,
|
float sunHaloFallof,
|
||||||
bool shadows);
|
bool shadows);
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_light(const void *const viewer, EntityId entityId);
|
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, EntityId entityId);
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_lights(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances);
|
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, EntityId light, float x, float y, float z);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length);
|
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, EntityId light, float x, float y, float z);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath);
|
EMSCRIPTEN_KEEPALIVE EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances, bool keepData);
|
||||||
|
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length, bool keepData, int priority, int layer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath, bool keepData);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId create_instance(void *sceneManager, EntityId id);
|
EMSCRIPTEN_KEEPALIVE EntityId create_instance(void *sceneManager, EntityId id);
|
||||||
EMSCRIPTEN_KEEPALIVE int get_instance_count(void *sceneManager, EntityId entityId);
|
EMSCRIPTEN_KEEPALIVE int get_instance_count(void *sceneManager, EntityId entityId);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_instances(void *sceneManager, EntityId entityId, EntityId *out);
|
EMSCRIPTEN_KEEPALIVE void get_instances(void *sceneManager, EntityId entityId, EntityId *out);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_main_camera(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void set_main_camera(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE bool set_camera(const void *const viewer, EntityId entity, const char *nodeName);
|
EMSCRIPTEN_KEEPALIVE bool set_camera(TViewer *viewer, EntityId entity, const char *nodeName);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(const void *const viewer, bool enabled);
|
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled);
|
||||||
EMSCRIPTEN_KEEPALIVE void render(
|
EMSCRIPTEN_KEEPALIVE bool render(
|
||||||
const void *const viewer,
|
TViewer *viewer,
|
||||||
uint64_t frameTimeInNanos,
|
uint64_t frameTimeInNanos,
|
||||||
void *pixelBuffer,
|
void *pixelBuffer,
|
||||||
void (*callback)(void *buf, size_t size, void *data),
|
void (*callback)(void *buf, size_t size, void *data),
|
||||||
void *data);
|
void *data);
|
||||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(const void *const viewer, const void *const window, uint32_t width, uint32_t height);
|
EMSCRIPTEN_KEEPALIVE void capture(
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(const void *const viewer);
|
TViewer *viewer,
|
||||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(const void *const viewer, float interval);
|
uint8_t *pixelBuffer,
|
||||||
EMSCRIPTEN_KEEPALIVE void update_viewport_and_camera_projection(const void *const viewer, uint32_t width, uint32_t height, float scaleFactor);
|
void (*callback)(void));
|
||||||
EMSCRIPTEN_KEEPALIVE void scroll_begin(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void create_swap_chain(TViewer *viewer, const void *const window, uint32_t width, uint32_t height);
|
||||||
EMSCRIPTEN_KEEPALIVE void scroll_update(const void *const viewer, float x, float y, float z);
|
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void scroll_end(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void set_frame_interval(TViewer *viewer, float interval);
|
||||||
EMSCRIPTEN_KEEPALIVE void grab_begin(const void *const viewer, float x, float y, bool pan);
|
EMSCRIPTEN_KEEPALIVE void update_viewport(TViewer *viewer, uint32_t width, uint32_t height);
|
||||||
EMSCRIPTEN_KEEPALIVE void grab_update(const void *const viewer, float x, float y);
|
EMSCRIPTEN_KEEPALIVE void scroll_begin(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void grab_end(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void scroll_update(TViewer *viewer, float x, float y, float z);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void scroll_end(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void grab_begin(TViewer *viewer, float x, float y, bool pan);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void grab_update(TViewer *viewer, float x, float y);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void grab_end(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE void apply_weights(
|
EMSCRIPTEN_KEEPALIVE void apply_weights(
|
||||||
void *sceneManager,
|
void *sceneManager,
|
||||||
EntityId entity,
|
EntityId entity,
|
||||||
@@ -136,6 +146,11 @@ extern "C"
|
|||||||
int numMorphTargets,
|
int numMorphTargets,
|
||||||
int numFrames,
|
int numFrames,
|
||||||
float frameLengthInMs);
|
float frameLengthInMs);
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(void *const sceneManager, TMaterialKey materialConfig);
|
||||||
|
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_unlit_material_instance(void *const sceneManager);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_material_instance(void *const sceneManager, TMaterialInstance *instance);
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(
|
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(
|
||||||
void *sceneManager,
|
void *sceneManager,
|
||||||
EntityId entity);
|
EntityId entity);
|
||||||
@@ -155,82 +170,86 @@ extern "C"
|
|||||||
float fadeInInSecs,
|
float fadeInInSecs,
|
||||||
float maxDelta);
|
float maxDelta);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_local_transform(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_local_transform(void *sceneManager,
|
||||||
EntityId entityId, float* const);
|
EntityId entityId, float *const);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(void *sceneManager,
|
||||||
EntityId entityId, int skinIndex, float* const out, int numBones);
|
EntityId entityId, int skinIndex, float *const out, int numBones);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_world_transform(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_world_transform(void *sceneManager,
|
||||||
EntityId entityId, float* const);
|
EntityId entityId, float *const);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(void *sceneManager,
|
||||||
EntityId entityId, int skinIndex, int boneIndex, float* const);
|
EntityId entityId, int skinIndex, int boneIndex, float *const);
|
||||||
EMSCRIPTEN_KEEPALIVE bool set_bone_transform(
|
EMSCRIPTEN_KEEPALIVE bool set_bone_transform(
|
||||||
void *sceneManager,
|
void *sceneManager,
|
||||||
EntityId entity,
|
EntityId entity,
|
||||||
int skinIndex,
|
int skinIndex,
|
||||||
int boneIndex,
|
int boneIndex,
|
||||||
const float *const transform);
|
const float *const transform);
|
||||||
EMSCRIPTEN_KEEPALIVE void play_animation(void *sceneManager, EntityId entity, int index, bool loop, bool reverse, bool replaceActive, float crossfade);
|
EMSCRIPTEN_KEEPALIVE void play_animation(void *sceneManager, EntityId entity, int index, bool loop, bool reverse, bool replaceActive, float crossfade, float startOffset);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame(void *sceneManager, EntityId entity, int animationIndex, int animationFrame);
|
EMSCRIPTEN_KEEPALIVE void set_animation_frame(void *sceneManager, EntityId entity, int animationIndex, int animationFrame);
|
||||||
EMSCRIPTEN_KEEPALIVE void stop_animation(void *sceneManager, EntityId entity, int index);
|
EMSCRIPTEN_KEEPALIVE void stop_animation(void *sceneManager, EntityId entity, int index);
|
||||||
EMSCRIPTEN_KEEPALIVE int get_animation_count(void *sceneManager, EntityId asset);
|
EMSCRIPTEN_KEEPALIVE int get_animation_count(void *sceneManager, EntityId asset);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_animation_name(void *sceneManager, EntityId entity, char *const outPtr, int index);
|
EMSCRIPTEN_KEEPALIVE void get_animation_name(void *sceneManager, EntityId entity, char *const outPtr, int index);
|
||||||
EMSCRIPTEN_KEEPALIVE float get_animation_duration(void *sceneManager, EntityId entity, int index);
|
EMSCRIPTEN_KEEPALIVE float get_animation_duration(void *sceneManager, EntityId entity, int index);
|
||||||
EMSCRIPTEN_KEEPALIVE int get_bone_count(void *sceneManager, EntityId assetEntity, int skinIndex);
|
EMSCRIPTEN_KEEPALIVE int get_bone_count(void *sceneManager, EntityId assetEntity, int skinIndex);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char** outPtr, int skinIndex);
|
EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char **outPtr, int skinIndex);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId get_bone(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE EntityId get_bone(void *sceneManager,
|
||||||
EntityId entityId,
|
EntityId entityId,
|
||||||
int skinIndex,
|
int skinIndex,
|
||||||
int boneIndex);
|
int boneIndex);
|
||||||
EMSCRIPTEN_KEEPALIVE bool set_transform(void* sceneManager, EntityId entityId, const float* const transform);
|
EMSCRIPTEN_KEEPALIVE bool set_transform(void *sceneManager, EntityId entityId, const float *const transform);
|
||||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(void* sceneManager, EntityId entityId);
|
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(void *sceneManager, EntityId entityId);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(void *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index);
|
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(void *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index);
|
||||||
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(void *sceneManager, EntityId assetEntity, EntityId childEntity);
|
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(void *sceneManager, EntityId assetEntity, EntityId childEntity);
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_entity(const void *const viewer, EntityId asset);
|
EMSCRIPTEN_KEEPALIVE void remove_entity(TViewer *viewer, EntityId asset);
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_entities(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void clear_entities(TViewer *viewer);
|
||||||
EMSCRIPTEN_KEEPALIVE bool set_material_color(void *sceneManager, EntityId entity, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a);
|
EMSCRIPTEN_KEEPALIVE bool set_material_color(void *sceneManager, EntityId entity, const char *meshName, int materialIndex, const float r, const float g, const float b, const float a);
|
||||||
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(void *sceneManager, EntityId asset);
|
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(void *sceneManager, EntityId asset);
|
||||||
EMSCRIPTEN_KEEPALIVE void queue_position_update(void *sceneManager, EntityId entity, float x, float y, float z, bool relative);
|
EMSCRIPTEN_KEEPALIVE void queue_position_update(void *sceneManager, EntityId entity, float x, float y, float z, bool relative);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(void *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(void *sceneManager, EntityId entity, float viewportX, float viewportY);
|
||||||
EMSCRIPTEN_KEEPALIVE void queue_rotation_update(void *sceneManager, EntityId entity, float rads, float x, float y, float z, float w, bool relative);
|
EMSCRIPTEN_KEEPALIVE void queue_rotation_update(void *sceneManager, EntityId entity, float rads, float x, float y, float z, float w, bool relative);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_position(void *sceneManager, EntityId entity, float x, float y, float z);
|
EMSCRIPTEN_KEEPALIVE void set_position(void *sceneManager, EntityId entity, float x, float y, float z);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_rotation(void *sceneManager, EntityId entity, float rads, float x, float y, float z, float w);
|
EMSCRIPTEN_KEEPALIVE void set_rotation(void *sceneManager, EntityId entity, float rads, float x, float y, float z, float w);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_scale(void *sceneManager, EntityId entity, float scale);
|
EMSCRIPTEN_KEEPALIVE void set_scale(void *sceneManager, EntityId entity, float scale);
|
||||||
|
|
||||||
// Camera methods
|
// Camera methods
|
||||||
EMSCRIPTEN_KEEPALIVE void move_camera_to_asset(const void *const viewer, EntityId asset);
|
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(const void *const viewer, bool enabled);
|
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(const void *const viewer, float aperture, float shutterSpeed, float sensitivity);
|
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_position(const void *const viewer, float x, float y, float z);
|
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_camera_position(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_rotation(const void *const viewer, float w, float x, float y, float z);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(const void *const viewer, const float *const matrix);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_model_matrix(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_view_matrix(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_projection_matrix(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(const void *const viewer, const double *const matrix, double near, double far);
|
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_culling(const void *const viewer, double near, double far);
|
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
|
||||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_near(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera);
|
||||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera);
|
||||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_culling_projection_matrix(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal);
|
||||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(const void *const viewer);
|
EMSCRIPTEN_KEEPALIVE void set_camera_lens_projection(TCamera *camera, double near, double far, double aspect, double focalLength);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_fov(const void *const viewer, float fovInDegrees, float aspect);
|
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float focusDistance);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_focal_length(const void *const viewer, float focalLength);
|
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(TViewer *viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(const void *const viewer, float focusDistance);
|
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* camera, double4x4 projectionMatrix, double near, double far);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
EMSCRIPTEN_KEEPALIVE TCamera *get_camera_component(TEngine *engine, EntityId entity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE int hide_mesh(void *sceneManager, EntityId entity, const char *meshName);
|
EMSCRIPTEN_KEEPALIVE int hide_mesh(void *sceneManager, EntityId entity, const char *meshName);
|
||||||
EMSCRIPTEN_KEEPALIVE int reveal_mesh(void *sceneManager, EntityId entity, const char *meshName);
|
EMSCRIPTEN_KEEPALIVE int reveal_mesh(void *sceneManager, EntityId entity, const char *meshName);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(void *const viewer, bool enabled);
|
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(void *const viewer, bool enabled);
|
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(TViewer *viewer, bool enabled);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_shadow_type(void *const viewer, int shadowType);
|
EMSCRIPTEN_KEEPALIVE void set_shadow_type(TViewer *viewer, int shadowType);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(void *const viewer, float penumbraScale, float penumbraRatioScale);
|
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(TViewer *viewer, float penumbraScale, float penumbraRatioScale);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_antialiasing(void *const viewer, bool msaa, bool fxaa, bool taa);
|
EMSCRIPTEN_KEEPALIVE void set_antialiasing(TViewer *viewer, bool msaa, bool fxaa, bool taa);
|
||||||
EMSCRIPTEN_KEEPALIVE void filament_pick(void *const viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
EMSCRIPTEN_KEEPALIVE void filament_pick(TViewer *viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||||
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(void *const sceneManager, const EntityId entityId);
|
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(void *const sceneManager, const EntityId entityId);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char *name);
|
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char *name);
|
||||||
EMSCRIPTEN_KEEPALIVE int get_entity_count(void *const sceneManager, const EntityId target, bool renderableOnly);
|
EMSCRIPTEN_KEEPALIVE int get_entity_count(void *const sceneManager, const EntityId target, bool renderableOnly);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_entities(void *const sceneManager, const EntityId target, bool renderableOnly, EntityId *out);
|
EMSCRIPTEN_KEEPALIVE void get_entities(void *const sceneManager, const EntityId target, bool renderableOnly, EntityId *out);
|
||||||
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly);
|
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(void *const sceneManager, const EntityId target, int index, bool renderableOnly);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_recording(void *const viewer, bool recording);
|
EMSCRIPTEN_KEEPALIVE void set_recording(TViewer *viewer, bool recording);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(void *const viewer, const char *outputDirectory);
|
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(TViewer *viewer, const char *outputDirectory);
|
||||||
EMSCRIPTEN_KEEPALIVE void ios_dummy();
|
EMSCRIPTEN_KEEPALIVE void ios_dummy();
|
||||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
|
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
|
||||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(void *const sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
EMSCRIPTEN_KEEPALIVE void add_collision_component(void *const sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
||||||
@@ -238,12 +257,47 @@ extern "C"
|
|||||||
EMSCRIPTEN_KEEPALIVE bool add_animation_component(void *const sceneManager, EntityId entityId);
|
EMSCRIPTEN_KEEPALIVE bool add_animation_component(void *const sceneManager, EntityId entityId);
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_animation_component(void *const sceneManager, EntityId entityId);
|
EMSCRIPTEN_KEEPALIVE void remove_animation_component(void *const sceneManager, EntityId entityId);
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId create_geometry(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath);
|
EMSCRIPTEN_KEEPALIVE EntityId create_geometry(
|
||||||
|
void *const sceneManager,
|
||||||
|
float *vertices,
|
||||||
|
int numVertices,
|
||||||
|
float *normals,
|
||||||
|
int numNormals,
|
||||||
|
float *uvs,
|
||||||
|
int numUvs,
|
||||||
|
uint16_t *indices,
|
||||||
|
int numIndices,
|
||||||
|
int primitiveType,
|
||||||
|
TMaterialInstance *materialInstance,
|
||||||
|
bool keepData);
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId get_parent(void *const sceneManager, EntityId child);
|
EMSCRIPTEN_KEEPALIVE EntityId get_parent(void *const sceneManager, EntityId child);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_parent(void *const sceneManager, EntityId child, EntityId parent);
|
EMSCRIPTEN_KEEPALIVE EntityId get_ancestor(void *const sceneManager, EntityId child);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_parent(void *const sceneManager, EntityId child, EntityId parent, bool preserveScaling);
|
||||||
EMSCRIPTEN_KEEPALIVE void test_collisions(void *const sceneManager, EntityId entity);
|
EMSCRIPTEN_KEEPALIVE void test_collisions(void *const sceneManager, EntityId entity);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_priority(void *const sceneManager, EntityId entityId, int priority);
|
EMSCRIPTEN_KEEPALIVE void set_priority(void *const sceneManager, EntityId entityId, int priority);
|
||||||
EMSCRIPTEN_KEEPALIVE void get_gizmo(void *const sceneManager, EntityId *out);
|
EMSCRIPTEN_KEEPALIVE void get_gizmo(void *const sceneManager, EntityId *out);
|
||||||
|
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(void *const sceneManager, EntityId entity);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(void *const sceneManager, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_layer_visibility(void *const sceneManager, int layer, bool visible);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_visibility_layer(void *const sceneManager, EntityId entity, int layer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void pick_gizmo(void *const sceneManager, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_gizmo_visibility(void *const sceneManager, bool visible);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(void *const sceneManager, EntityId entity, float r, float g, float b);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(void *const sceneManager, EntityId entity);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_property_float(void *const sceneManager, EntityId entity, int materialIndex, const char *property, float value);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_property_int(void *const sceneManager, EntityId entity, int materialIndex, const char *property, int value);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(void *const sceneManager, EntityId entity, int materialIndex, const char *property, double4 value);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_depth_write(void *const sceneManager, EntityId entity, int materialIndex, bool enabled);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer* viewer, EntityId entity,uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void *const create_texture(void *const sceneManager, uint8_t *data, size_t length);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_texture(void *const sceneManager, void *const texture);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(void *const sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex);
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TMaterialInstance* get_material_instance_at(void *const sceneManager, EntityId entity, int materialIndex);
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* materialInstance, bool enabled);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled);
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
#ifndef _DART_FILAMENT_FFI_API_H
|
|
||||||
#define _DART_FILAMENT_FFI_API_H
|
|
||||||
|
|
||||||
#include "ThermionDartApi.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
|
|
||||||
///
|
|
||||||
/// This header replicates most of the methods in ThermionDartApi.h.
|
|
||||||
/// It represents the interface for:
|
|
||||||
/// - invoking those methods that must be called on the main Filament engine thread
|
|
||||||
/// - setting up a render loop
|
|
||||||
///
|
|
||||||
typedef int32_t EntityId;
|
|
||||||
typedef void (*FilamentRenderCallback)(void *const owner);
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_ffi(
|
|
||||||
void *const context,
|
|
||||||
void *const platform,
|
|
||||||
const char *uberArchivePath,
|
|
||||||
const void *const loader,
|
|
||||||
void (*renderCallback)(void *const renderCallbackOwner),
|
|
||||||
void *const renderCallbackOwner,
|
|
||||||
void (*callback)(void *const viewer));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_ffi(void *const viewer, void (*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_render_target_ffi(void *const viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void render_ffi(void *const viewer);
|
|
||||||
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_rendering_ffi(void *const viewer, bool rendering, void(*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval_ffi(void *const viewer, float frameInterval);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void update_viewport_and_camera_projection_ffi(void *const viewer, const uint32_t width, const uint32_t height, const float scaleFactor, void (*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_color_ffi(void *const viewer, const float r, const float g, const float b, const float a);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_background_image_ffi(void *const viewer);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image_ffi(void *const viewer, const char *path, bool fillHeight, void (*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_ffi(void *const viewer, float x, float y, bool clamp);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_ffi(void *const viewer, int toneMapping);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_bloom_ffi(void *const viewer, float strength);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_skybox_ffi(void *const viewer, const char *skyboxPath, void (*onComplete)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_ibl_ffi(void *const viewer, const char *iblPath, float intensity);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_ffi(void *const viewer);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_ibl_ffi(void *const viewer);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void add_light_ffi(
|
|
||||||
void *const viewer,
|
|
||||||
uint8_t type,
|
|
||||||
float colour,
|
|
||||||
float intensity,
|
|
||||||
float posX,
|
|
||||||
float posY,
|
|
||||||
float posZ,
|
|
||||||
float dirX,
|
|
||||||
float dirY,
|
|
||||||
float dirZ,
|
|
||||||
float falloffRadius,
|
|
||||||
float spotLightConeInner,
|
|
||||||
float spotLightConeOuter,
|
|
||||||
float sunAngularRadius,
|
|
||||||
float sunHaloSize,
|
|
||||||
float sunHaloFallof,
|
|
||||||
bool shadows,
|
|
||||||
void (*callback)(EntityId));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_light_ffi(void *const viewer, EntityId entityId);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_lights_ffi(void *const viewer);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_glb_ffi(void *const sceneManager, const char *assetPath, int numInstances, void (*callback)(EntityId));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_ffi(void *const sceneManager, const void *const data, size_t length, int numInstances, void (*callback)(EntityId));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_gltf_ffi(void *const sceneManager, const char *assetPath, const char *relativePath, void (*callback)(EntityId));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_instance_ffi(void *const sceneManager, EntityId entityId, void (*callback)(EntityId));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_entity_ffi(void *const viewer, EntityId asset, void (*callback)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_entities_ffi(void *const viewer, void (*callback)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_ffi(void *const viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void apply_weights_ffi(
|
|
||||||
void *const sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
const char *const entityName,
|
|
||||||
float *const weights,
|
|
||||||
int count);
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void play_animation_ffi(void *const sceneManager, EntityId asset, int index, bool loop, bool reverse, bool replaceActive, float crossfade);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame_ffi(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void stop_animation_ffi(void *const sceneManager, EntityId asset, int index);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_animation_count_ffi(void *const sceneManager, EntityId asset, void (*callback)(int));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_animation_name_ffi(void *const sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_ffi(void *const sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_ffi(void *const sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_ffi(void *const sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
const float *const morphData,
|
|
||||||
int numWeights,
|
|
||||||
void (*callback)(bool));
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_ffi(void *sceneManager,
|
|
||||||
EntityId asset, void(*callback)(bool));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_bone_transform_ffi(
|
|
||||||
void *sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
int skinIndex,
|
|
||||||
int boneIndex,
|
|
||||||
const float *const transform,
|
|
||||||
void (*callback)(bool));
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_post_processing_ffi(void *const viewer, bool enabled);
|
|
||||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_ffi(void *const sceneManager, EntityId entityId, void(*callback)());
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_geometry_ffi(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath, void (*callback)(EntityId));
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // _DART_FILAMENT_FFI_API_H
|
|
||||||
126
thermion_dart/native/include/ThermionDartRenderThreadApi.h
Normal file
126
thermion_dart/native/include/ThermionDartRenderThreadApi.h
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
#ifndef _DART_FILAMENT_FFI_API_H
|
||||||
|
#define _DART_FILAMENT_FFI_API_H
|
||||||
|
|
||||||
|
#include "ThermionDartApi.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///
|
||||||
|
/// This header replicates most of the methods in ThermionDartApi.h.
|
||||||
|
/// It represents the interface for:
|
||||||
|
/// - invoking those methods that must be called on the main Filament engine thread
|
||||||
|
/// - setting up a render loop
|
||||||
|
///
|
||||||
|
typedef int32_t EntityId;
|
||||||
|
typedef void (*FilamentRenderCallback)(void *const owner);
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_render_thread(
|
||||||
|
void *const context,
|
||||||
|
void *const platform,
|
||||||
|
const char *uberArchivePath,
|
||||||
|
const void *const loader,
|
||||||
|
void (*renderCallback)(void *const renderCallbackOwner),
|
||||||
|
void *const renderCallbackOwner,
|
||||||
|
void (*callback)(TViewer *viewer));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(TViewer *viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(TViewer *viewer, void (*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(TViewer *viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void render_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void capture_render_thread(TViewer *viewer, uint8_t* out, void (*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void(*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(TViewer *viewer, int toneMapping);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(TViewer *viewer, float strength);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_ibl_render_thread(TViewer *viewer, const char *iblPath, float intensity);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_ibl_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void add_light_render_thread(
|
||||||
|
TViewer *viewer,
|
||||||
|
uint8_t type,
|
||||||
|
float colour,
|
||||||
|
float intensity,
|
||||||
|
float posX,
|
||||||
|
float posY,
|
||||||
|
float posZ,
|
||||||
|
float dirX,
|
||||||
|
float dirY,
|
||||||
|
float dirZ,
|
||||||
|
float falloffRadius,
|
||||||
|
float spotLightConeInner,
|
||||||
|
float spotLightConeOuter,
|
||||||
|
float sunAngularRadius,
|
||||||
|
float sunHaloSize,
|
||||||
|
float sunHaloFallof,
|
||||||
|
bool shadows,
|
||||||
|
void (*callback)(EntityId));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_light_render_thread(TViewer *viewer, EntityId entityId);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void clear_lights_render_thread(TViewer *viewer);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(void *const sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(void *const sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, void (*callback)(EntityId));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(void *const sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_instance_render_thread(void *const sceneManager, EntityId entityId, void (*callback)(EntityId));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer, EntityId asset, void (*callback)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(TViewer *viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void apply_weights_render_thread(
|
||||||
|
void *const sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
const char *const entityName,
|
||||||
|
float *const weights,
|
||||||
|
int count);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(void *const sceneManager, EntityId asset, int index);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(void *const sceneManager, EntityId asset, void (*callback)(int));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(void *const sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_render_thread(void *const sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_render_thread(void *const sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(void *const sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
const float *const morphData,
|
||||||
|
int numWeights,
|
||||||
|
void (*callback)(bool));
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(void *sceneManager,
|
||||||
|
EntityId asset, void(*callback)(bool));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
|
||||||
|
void *sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
int skinIndex,
|
||||||
|
int boneIndex,
|
||||||
|
const float *const transform,
|
||||||
|
void (*callback)(bool));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer, bool enabled);
|
||||||
|
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(void *const sceneManager, EntityId entityId, void(*callback)());
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
|
||||||
|
void *const sceneManager,
|
||||||
|
float *vertices,
|
||||||
|
int numVertices,
|
||||||
|
float *normals,
|
||||||
|
int numNormals,
|
||||||
|
float *uvs,
|
||||||
|
int numUvs,
|
||||||
|
uint16_t *indices,
|
||||||
|
int numIndices,
|
||||||
|
int primitiveType,
|
||||||
|
TMaterialInstance *materialInstance,
|
||||||
|
bool keepData,
|
||||||
|
void (*callback)(EntityId));
|
||||||
|
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)());
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // _DART_FILAMENT_FFI_API_H
|
||||||
39
thermion_dart/native/include/UnprojectTexture.hpp
Normal file
39
thermion_dart/native/include/UnprojectTexture.hpp
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/Camera.h>
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
#include <filament/VertexBuffer.h>
|
||||||
|
#include <filament/IndexBuffer.h>
|
||||||
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/TransformManager.h>
|
||||||
|
#include <math/mat4.h>
|
||||||
|
#include <math/vec2.h>
|
||||||
|
#include <math/vec3.h>
|
||||||
|
#include <math/vec4.h>
|
||||||
|
#include <utils/EntityManager.h>
|
||||||
|
#include <backend/PixelBufferDescriptor.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "CustomGeometry.hpp"
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
class UnprojectTexture {
|
||||||
|
public:
|
||||||
|
UnprojectTexture(const CustomGeometry * geometry, Camera& camera, Engine* engine)
|
||||||
|
: _geometry(geometry), _camera(camera), _engine(engine) {}
|
||||||
|
|
||||||
|
void unproject(utils::Entity entity, const uint8_t* inputTexture, uint8_t* outputTexture, uint32_t inputWidth, uint32_t inputHeight,
|
||||||
|
uint32_t outputWidth, uint32_t outputHeight);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CustomGeometry * _geometry;
|
||||||
|
const Camera& _camera;
|
||||||
|
Engine* _engine;
|
||||||
|
|
||||||
|
math::float3 doUnproject(const math::float2& screenPos, float depth, const math::mat4& invViewProj);
|
||||||
|
bool isInsideTriangle(const math::float2& p, const math::float2& a, const math::float2& b, const math::float2& c);
|
||||||
|
math::float3 barycentric(const math::float2& p, const math::float2& a, const math::float2& b, const math::float2& c);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -43,6 +43,7 @@ namespace thermion_filament
|
|||||||
struct AnimationStatus
|
struct AnimationStatus
|
||||||
{
|
{
|
||||||
time_point_t start = time_point_t::max();
|
time_point_t start = time_point_t::max();
|
||||||
|
float startOffset;
|
||||||
bool loop = false;
|
bool loop = false;
|
||||||
bool reverse = false;
|
bool reverse = false;
|
||||||
float durationInSecs = 0;
|
float durationInSecs = 0;
|
||||||
@@ -182,7 +183,7 @@ namespace thermion_filament
|
|||||||
|
|
||||||
auto animationStatus = animationComponent.gltfAnimations[i];
|
auto animationStatus = animationComponent.gltfAnimations[i];
|
||||||
|
|
||||||
auto elapsedInSecs = float(std::chrono::duration_cast<std::chrono::milliseconds>(now - animationStatus.start).count()) / 1000.0f;
|
auto elapsedInSecs = animationStatus.startOffset + float(std::chrono::duration_cast<std::chrono::milliseconds>(now - animationStatus.start).count()) / 1000.0f;
|
||||||
|
|
||||||
if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
|
if (!animationStatus.loop && elapsedInSecs >= animationStatus.durationInSecs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef UNLIT_MATERIAL_PROVIDER_HPP
|
||||||
|
#define UNLIT_MATERIAL_PROVIDER_HPP
|
||||||
|
|
||||||
|
#include <filament/gltfio/MaterialProvider.h>
|
||||||
|
#include <filament/Material.h>
|
||||||
|
#include <filament/MaterialInstance.h>
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
#include <filament/TextureSampler.h>
|
||||||
|
#include <math/mat3.h>
|
||||||
|
#include <math/vec3.h>
|
||||||
|
#include <math/vec4.h>
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
class UnlitMaterialProvider : public filament::gltfio::MaterialProvider {
|
||||||
|
private:
|
||||||
|
filament::Material* mUnlitMaterial;
|
||||||
|
const filament::Material* mMaterials[1];
|
||||||
|
filament::Engine* mEngine;
|
||||||
|
|
||||||
|
public:
|
||||||
|
UnlitMaterialProvider(filament::Engine* engine, const void* const data, const size_t size) : mEngine(engine) {
|
||||||
|
mUnlitMaterial = filament::Material::Builder()
|
||||||
|
.package(data, size)
|
||||||
|
.build(*engine);
|
||||||
|
mMaterials[0] = mUnlitMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
~UnlitMaterialProvider() {
|
||||||
|
mEngine->destroy(mUnlitMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
filament::MaterialInstance* createMaterialInstance(filament::gltfio::MaterialKey* config,
|
||||||
|
filament::gltfio::UvMap* uvmap,
|
||||||
|
const char* label = "unlit",
|
||||||
|
const char* extras = nullptr) override {
|
||||||
|
auto instance = mUnlitMaterial->createInstance();
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
filament::Material* getMaterial(filament::gltfio::MaterialKey* config,
|
||||||
|
filament::gltfio::UvMap* uvmap,
|
||||||
|
const char* label = "unlit") override {
|
||||||
|
return mUnlitMaterial;
|
||||||
|
}
|
||||||
|
|
||||||
|
const filament::Material* const* getMaterials() const noexcept override {
|
||||||
|
return mMaterials;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getMaterialsCount() const noexcept override {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyMaterials() override {
|
||||||
|
// Materials are destroyed in the destructor
|
||||||
|
}
|
||||||
|
|
||||||
|
bool needsDummyData(filament::VertexAttribute attrib) const noexcept override {
|
||||||
|
// For unlit material, we don't need dummy data for any attribute
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace thermion_filament
|
||||||
|
|
||||||
|
#endif // UNLIT_MATERIAL_PROVIDER_HPP
|
||||||
@@ -8,5 +8,5 @@ GIZMO_PACKAGE:
|
|||||||
GIZMO_GIZMO_OFFSET:
|
GIZMO_GIZMO_OFFSET:
|
||||||
.int 0
|
.int 0
|
||||||
GIZMO_GIZMO_SIZE:
|
GIZMO_GIZMO_SIZE:
|
||||||
.int 26876
|
.int 27809
|
||||||
|
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ _GIZMO_PACKAGE:
|
|||||||
_GIZMO_GIZMO_OFFSET:
|
_GIZMO_GIZMO_OFFSET:
|
||||||
.int 0
|
.int 0
|
||||||
_GIZMO_GIZMO_SIZE:
|
_GIZMO_GIZMO_SIZE:
|
||||||
.int 26876
|
.int 27809
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,11 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
extern "C" {
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
extern const uint8_t GIZMO_PACKAGE[];
|
extern const uint8_t GIZMO_PACKAGE[];
|
||||||
extern int GIZMO_GIZMO_OFFSET;
|
extern int GIZMO_GIZMO_OFFSET;
|
||||||
extern int GIZMO_GIZMO_SIZE;
|
extern int GIZMO_GIZMO_SIZE;
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#define GIZMO_GIZMO_DATA (GIZMO_PACKAGE + GIZMO_GIZMO_OFFSET)
|
#define GIZMO_GIZMO_DATA (GIZMO_PACKAGE + GIZMO_GIZMO_OFFSET)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
12
thermion_dart/native/include/material/grid.S
Normal file
12
thermion_dart/native/include/material/grid.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.global GRID_GRID_OFFSET;
|
||||||
|
.global GRID_GRID_SIZE;
|
||||||
|
|
||||||
|
.global GRID_PACKAGE
|
||||||
|
.section .rodata
|
||||||
|
GRID_PACKAGE:
|
||||||
|
.incbin "grid.bin"
|
||||||
|
GRID_GRID_OFFSET:
|
||||||
|
.int 0
|
||||||
|
GRID_GRID_SIZE:
|
||||||
|
.int 30210
|
||||||
|
|
||||||
12
thermion_dart/native/include/material/grid.apple.S
Normal file
12
thermion_dart/native/include/material/grid.apple.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.global _GRID_GRID_OFFSET;
|
||||||
|
.global _GRID_GRID_SIZE;
|
||||||
|
|
||||||
|
.global _GRID_PACKAGE
|
||||||
|
.section __TEXT,__const
|
||||||
|
_GRID_PACKAGE:
|
||||||
|
.incbin "grid.bin"
|
||||||
|
_GRID_GRID_OFFSET:
|
||||||
|
.int 0
|
||||||
|
_GRID_GRID_SIZE:
|
||||||
|
.int 30210
|
||||||
|
|
||||||
BIN
thermion_dart/native/include/material/grid.bin
Normal file
BIN
thermion_dart/native/include/material/grid.bin
Normal file
Binary file not shown.
1521
thermion_dart/native/include/material/grid.c
Normal file
1521
thermion_dart/native/include/material/grid.c
Normal file
File diff suppressed because it is too large
Load Diff
13
thermion_dart/native/include/material/grid.h
Normal file
13
thermion_dart/native/include/material/grid.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef GRID_H_
|
||||||
|
#define GRID_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
extern const uint8_t GRID_PACKAGE[];
|
||||||
|
extern int GRID_GRID_OFFSET;
|
||||||
|
extern int GRID_GRID_SIZE;
|
||||||
|
}
|
||||||
|
#define GRID_GRID_DATA (GRID_PACKAGE + GRID_GRID_OFFSET)
|
||||||
|
|
||||||
|
#endif
|
||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -3,16 +3,11 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
extern "C" {
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
extern const uint8_t IMAGE_PACKAGE[];
|
extern const uint8_t IMAGE_PACKAGE[];
|
||||||
extern int IMAGE_IMAGE_OFFSET;
|
extern int IMAGE_IMAGE_OFFSET;
|
||||||
extern int IMAGE_IMAGE_SIZE;
|
extern int IMAGE_IMAGE_SIZE;
|
||||||
#if defined(__cplusplus)
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
#define IMAGE_IMAGE_DATA (IMAGE_PACKAGE + IMAGE_IMAGE_OFFSET)
|
#define IMAGE_IMAGE_DATA (IMAGE_PACKAGE + IMAGE_IMAGE_OFFSET)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
12
thermion_dart/native/include/material/unlit.S
Normal file
12
thermion_dart/native/include/material/unlit.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.global UNLIT_UNLIT_OFFSET;
|
||||||
|
.global UNLIT_UNLIT_SIZE;
|
||||||
|
|
||||||
|
.global UNLIT_PACKAGE
|
||||||
|
.section .rodata
|
||||||
|
UNLIT_PACKAGE:
|
||||||
|
.incbin "unlit.bin"
|
||||||
|
UNLIT_UNLIT_OFFSET:
|
||||||
|
.int 0
|
||||||
|
UNLIT_UNLIT_SIZE:
|
||||||
|
.int 101394
|
||||||
|
|
||||||
12
thermion_dart/native/include/material/unlit.apple.S
Normal file
12
thermion_dart/native/include/material/unlit.apple.S
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
.global _UNLIT_UNLIT_OFFSET;
|
||||||
|
.global _UNLIT_UNLIT_SIZE;
|
||||||
|
|
||||||
|
.global _UNLIT_PACKAGE
|
||||||
|
.section __TEXT,__const
|
||||||
|
_UNLIT_PACKAGE:
|
||||||
|
.incbin "unlit.bin"
|
||||||
|
_UNLIT_UNLIT_OFFSET:
|
||||||
|
.int 0
|
||||||
|
_UNLIT_UNLIT_SIZE:
|
||||||
|
.int 101394
|
||||||
|
|
||||||
BIN
thermion_dart/native/include/material/unlit.bin
Normal file
BIN
thermion_dart/native/include/material/unlit.bin
Normal file
Binary file not shown.
5080
thermion_dart/native/include/material/unlit.c
Normal file
5080
thermion_dart/native/include/material/unlit.c
Normal file
File diff suppressed because it is too large
Load Diff
13
thermion_dart/native/include/material/unlit.h
Normal file
13
thermion_dart/native/include/material/unlit.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef UNLIT_H_
|
||||||
|
#define UNLIT_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
extern const uint8_t UNLIT_PACKAGE[];
|
||||||
|
extern int UNLIT_UNLIT_OFFSET;
|
||||||
|
extern int UNLIT_UNLIT_SIZE;
|
||||||
|
}
|
||||||
|
#define UNLIT_UNLIT_DATA (UNLIT_PACKAGE + UNLIT_UNLIT_OFFSET)
|
||||||
|
|
||||||
|
#endif
|
||||||
194
thermion_dart/native/src/CustomGeometry.cpp
Normal file
194
thermion_dart/native/src/CustomGeometry.cpp
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
#include <vector>
|
||||||
|
#include "math.h"
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/TransformManager.h>
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/Viewport.h>
|
||||||
|
#include <filament/Frustum.h>
|
||||||
|
#include <filament/geometry/SurfaceOrientation.h>
|
||||||
|
|
||||||
|
#include "Log.hpp"
|
||||||
|
#include "CustomGeometry.hpp"
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
using namespace filament;
|
||||||
|
|
||||||
|
CustomGeometry::CustomGeometry(
|
||||||
|
float* vertices,
|
||||||
|
uint32_t numVertices,
|
||||||
|
float* normals,
|
||||||
|
uint32_t numNormals,
|
||||||
|
float* uvs,
|
||||||
|
uint32_t numUvs,
|
||||||
|
uint16_t* indices,
|
||||||
|
uint32_t numIndices,
|
||||||
|
RenderableManager::PrimitiveType primitiveType,
|
||||||
|
Engine* engine)
|
||||||
|
: numVertices(numVertices), numIndices(numIndices), _engine(engine) {
|
||||||
|
this->primitiveType = primitiveType;
|
||||||
|
this->vertices = new float[numVertices];
|
||||||
|
std::memcpy(this->vertices, vertices, numVertices * sizeof(float));
|
||||||
|
|
||||||
|
if(numNormals > 0) {
|
||||||
|
Log("numNormals %d", numNormals);
|
||||||
|
this->normals = new float[numNormals];
|
||||||
|
std::memcpy(this->normals, normals, numNormals * sizeof(float));
|
||||||
|
} else {
|
||||||
|
Log("no normals");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(numUvs > 0) {
|
||||||
|
Log("numUvs %d", numUvs);
|
||||||
|
this->uvs = new float[numUvs];
|
||||||
|
std::memcpy(this->uvs, uvs, numUvs * sizeof(float));
|
||||||
|
} else {
|
||||||
|
this->uvs = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->indices = new uint16_t[numIndices];
|
||||||
|
std::memcpy(this->indices, indices, numIndices * sizeof(uint16_t));
|
||||||
|
|
||||||
|
computeBoundingBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
IndexBuffer* CustomGeometry::indexBuffer() const {
|
||||||
|
IndexBuffer::BufferDescriptor::Callback indexCallback = [](void *buf, size_t,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
// free((void *)buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto indexBuffer = IndexBuffer::Builder()
|
||||||
|
.indexCount(numIndices)
|
||||||
|
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||||
|
.build(*_engine);
|
||||||
|
|
||||||
|
indexBuffer->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||||
|
this->indices, indexBuffer->getIndexCount() * sizeof(uint16_t), indexCallback));
|
||||||
|
return indexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
VertexBuffer* CustomGeometry::vertexBuffer() const {
|
||||||
|
VertexBuffer::BufferDescriptor::Callback vertexCallback = [](void *buf, size_t,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
// free((void *)buf);
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<filament::math::ushort3> triangles;
|
||||||
|
for(int i=0; i < numIndices; i+=3) {
|
||||||
|
filament::math::ushort3 triangle;
|
||||||
|
triangle.x = this->indices[i];
|
||||||
|
triangle.y = this->indices[i+1];
|
||||||
|
triangle.z = this->indices[i+2];
|
||||||
|
triangles.push_back(triangle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a SurfaceOrientation builder
|
||||||
|
geometry::SurfaceOrientation::Builder builder;
|
||||||
|
builder.vertexCount(numVertices)
|
||||||
|
.normals((filament::math::float3*)normals)
|
||||||
|
.positions((filament::math::float3*)this->vertices)
|
||||||
|
.triangleCount(triangles.size())
|
||||||
|
.triangles(triangles.data());
|
||||||
|
|
||||||
|
// Build the SurfaceOrientation object
|
||||||
|
auto orientation = builder.build();
|
||||||
|
|
||||||
|
// Retrieve the quaternions
|
||||||
|
auto quats = new std::vector<filament::math::quatf>(numVertices);
|
||||||
|
orientation->getQuats(quats->data(), numVertices);
|
||||||
|
|
||||||
|
// Use provided UVs or create dummy UV data
|
||||||
|
std::vector<filament::math::float2>* uvData;
|
||||||
|
if (this->uvs != nullptr) {
|
||||||
|
uvData = new std::vector<filament::math::float2>((filament::math::float2*)this->uvs, (filament::math::float2*)(this->uvs + numVertices * 2));
|
||||||
|
} else {
|
||||||
|
uvData = new std::vector<filament::math::float2>(numVertices, filament::math::float2{0.0f, 0.0f});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create dummy vertex color data (white color for all vertices)
|
||||||
|
auto dummyColors = new std::vector<filament::math::float4>(numVertices, filament::math::float4{1.0f, 1.0f, 1.0f, 1.0f});
|
||||||
|
|
||||||
|
auto vertexBufferBuilder = VertexBuffer::Builder()
|
||||||
|
.vertexCount(numVertices)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.attribute(VertexAttribute::UV0, 1, VertexBuffer::AttributeType::FLOAT2)
|
||||||
|
.attribute(VertexAttribute::UV1, 2, VertexBuffer::AttributeType::FLOAT2)
|
||||||
|
.attribute(VertexAttribute::COLOR, 3, VertexBuffer::AttributeType::FLOAT4);
|
||||||
|
|
||||||
|
if(this->normals) {
|
||||||
|
vertexBufferBuilder
|
||||||
|
.bufferCount(5)
|
||||||
|
.attribute(VertexAttribute::TANGENTS, 4, filament::VertexBuffer::AttributeType::FLOAT4);
|
||||||
|
} else {
|
||||||
|
vertexBufferBuilder = vertexBufferBuilder.bufferCount(4);
|
||||||
|
}
|
||||||
|
auto vertexBuffer = vertexBufferBuilder
|
||||||
|
.build(*_engine);
|
||||||
|
|
||||||
|
vertexBuffer->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(
|
||||||
|
this->vertices, vertexBuffer->getVertexCount() * sizeof(math::float3), vertexCallback));
|
||||||
|
|
||||||
|
// Set UV0 buffer
|
||||||
|
vertexBuffer->setBufferAt(*_engine, 1, VertexBuffer::BufferDescriptor(
|
||||||
|
uvData->data(), uvData->size() * sizeof(math::float2),
|
||||||
|
[](void* buf, size_t, void* data) {
|
||||||
|
delete static_cast<std::vector<math::float2>*>(data);
|
||||||
|
}, uvData));
|
||||||
|
|
||||||
|
// Set UV1 buffer (reusing UV0 data)
|
||||||
|
vertexBuffer->setBufferAt(*_engine, 2, VertexBuffer::BufferDescriptor(
|
||||||
|
uvData->data(), uvData->size() * sizeof(math::float2),
|
||||||
|
[](void* buf, size_t, void* data) {
|
||||||
|
// Do nothing here, as we're reusing the same data as UV0
|
||||||
|
}, nullptr));
|
||||||
|
|
||||||
|
// Set vertex color buffer
|
||||||
|
vertexBuffer->setBufferAt(*_engine, 3, VertexBuffer::BufferDescriptor(
|
||||||
|
dummyColors->data(), dummyColors->size() * sizeof(math::float4),
|
||||||
|
[](void* buf, size_t, void* data) {
|
||||||
|
delete static_cast<std::vector<math::float4>*>(data);
|
||||||
|
}, dummyColors));
|
||||||
|
|
||||||
|
if(this->normals) {
|
||||||
|
vertexBuffer->setBufferAt(*_engine, 4, VertexBuffer::BufferDescriptor(
|
||||||
|
quats->data(), quats->size() * sizeof(math::quatf), [] (void *buf, size_t,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
|
delete (std::vector<math::quatf>*)data;
|
||||||
|
}, (void*)quats));
|
||||||
|
}
|
||||||
|
return vertexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomGeometry::~CustomGeometry() {
|
||||||
|
delete[] vertices;
|
||||||
|
delete[] indices;
|
||||||
|
if (normals) delete[] normals;
|
||||||
|
if (uvs) delete[] uvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CustomGeometry::computeBoundingBox() {
|
||||||
|
float minX = FLT_MAX, minY = FLT_MAX, minZ = FLT_MAX;
|
||||||
|
float maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < numVertices; i += 3) {
|
||||||
|
minX = std::min(vertices[i], minX);
|
||||||
|
minY = std::min(vertices[i + 1], minY);
|
||||||
|
minZ = std::min(vertices[i + 2], minZ);
|
||||||
|
maxX = std::max(vertices[i], maxX);
|
||||||
|
maxY = std::max(vertices[i + 1], maxY);
|
||||||
|
maxZ = std::max(vertices[i + 2], maxZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
boundingBox = Box{{minX, minY, minZ}, {maxX, maxY, maxZ}};
|
||||||
|
}
|
||||||
|
|
||||||
|
Box CustomGeometry::getBoundingBox() const {
|
||||||
|
return boundingBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
354
thermion_dart/native/src/Gizmo.cpp
Normal file
354
thermion_dart/native/src/Gizmo.cpp
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
#include "Gizmo.hpp"
|
||||||
|
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <utils/Entity.h>
|
||||||
|
#include <utils/EntityManager.h>
|
||||||
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/TransformManager.h>
|
||||||
|
#include <gltfio/math.h>
|
||||||
|
#include "SceneManager.hpp"
|
||||||
|
#include "material/gizmo.h"
|
||||||
|
#include "Log.hpp"
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
using namespace filament::gltfio;
|
||||||
|
|
||||||
|
Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||||
|
{
|
||||||
|
|
||||||
|
_scene = scene;
|
||||||
|
_view = view;
|
||||||
|
_camera = &(_view->getCamera());
|
||||||
|
|
||||||
|
auto &entityManager = EntityManager::get();
|
||||||
|
|
||||||
|
auto &transformManager = engine.getTransformManager();
|
||||||
|
|
||||||
|
_material =
|
||||||
|
Material::Builder()
|
||||||
|
.package(GIZMO_GIZMO_DATA, GIZMO_GIZMO_SIZE)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
// First, create the black cube at the center
|
||||||
|
// The axes widgets will be parented to this entity
|
||||||
|
_entities[3] = entityManager.create();
|
||||||
|
|
||||||
|
_materialInstances[3] = _material->createInstance();
|
||||||
|
_materialInstances[3]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 1.0f}); // Black color
|
||||||
|
|
||||||
|
// Create center cube vertices
|
||||||
|
float centerCubeSize = 0.01f;
|
||||||
|
float *centerCubeVertices = new float[8 * 3]{
|
||||||
|
-centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||||
|
centerCubeSize, -centerCubeSize, -centerCubeSize,
|
||||||
|
centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||||
|
-centerCubeSize, centerCubeSize, -centerCubeSize,
|
||||||
|
-centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||||
|
centerCubeSize, -centerCubeSize, centerCubeSize,
|
||||||
|
centerCubeSize, centerCubeSize, centerCubeSize,
|
||||||
|
-centerCubeSize, centerCubeSize, centerCubeSize};
|
||||||
|
|
||||||
|
// Create center cube indices
|
||||||
|
uint16_t *centerCubeIndices = new uint16_t[36]{
|
||||||
|
0, 1, 2, 2, 3, 0,
|
||||||
|
1, 5, 6, 6, 2, 1,
|
||||||
|
5, 4, 7, 7, 6, 5,
|
||||||
|
4, 0, 3, 3, 7, 4,
|
||||||
|
3, 2, 6, 6, 7, 3,
|
||||||
|
4, 5, 1, 1, 0, 4};
|
||||||
|
|
||||||
|
auto centerCubeVb = VertexBuffer::Builder()
|
||||||
|
.vertexCount(8)
|
||||||
|
.bufferCount(1)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
centerCubeVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||||
|
{ delete[] static_cast<float *>(buffer); }));
|
||||||
|
|
||||||
|
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(engine);
|
||||||
|
centerCubeIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||||
|
centerCubeIndices, 36 * sizeof(uint16_t),
|
||||||
|
[](void *buffer, size_t size, void *)
|
||||||
|
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||||
|
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({{-centerCubeSize, -centerCubeSize, -centerCubeSize},
|
||||||
|
{centerCubeSize, centerCubeSize, centerCubeSize}})
|
||||||
|
.material(0, _materialInstances[3])
|
||||||
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
|
.priority(7)
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||||
|
.culling(false)
|
||||||
|
.build(engine, _entities[3]);
|
||||||
|
|
||||||
|
auto cubeTransformInstance = transformManager.getInstance(_entities[3]);
|
||||||
|
math::mat4f cubeTransform;
|
||||||
|
transformManager.setTransform(cubeTransformInstance, cubeTransform);
|
||||||
|
|
||||||
|
// Line and arrow vertices
|
||||||
|
float lineLength = 0.6f;
|
||||||
|
float lineWidth = 0.004f;
|
||||||
|
float arrowLength = 0.06f;
|
||||||
|
float arrowWidth = 0.02f;
|
||||||
|
float *vertices = new float[13 * 3]{
|
||||||
|
// Line vertices (8 vertices)
|
||||||
|
-lineWidth, -lineWidth, 0.0f,
|
||||||
|
lineWidth, -lineWidth, 0.0f,
|
||||||
|
lineWidth, lineWidth, 0.0f,
|
||||||
|
-lineWidth, lineWidth, 0.0f,
|
||||||
|
-lineWidth, -lineWidth, lineLength,
|
||||||
|
lineWidth, -lineWidth, lineLength,
|
||||||
|
lineWidth, lineWidth, lineLength,
|
||||||
|
-lineWidth, lineWidth, lineLength,
|
||||||
|
// Arrow vertices (5 vertices)
|
||||||
|
0.0f, 0.0f, lineLength + arrowLength, // Tip of the arrow
|
||||||
|
-arrowWidth, -arrowWidth, lineLength, // Base of the arrow
|
||||||
|
arrowWidth, -arrowWidth, lineLength,
|
||||||
|
arrowWidth, arrowWidth, lineLength,
|
||||||
|
-arrowWidth, arrowWidth, lineLength};
|
||||||
|
|
||||||
|
// Line and arrow indices
|
||||||
|
uint16_t *indices = new uint16_t[54]{
|
||||||
|
// Line indices (24 indices)
|
||||||
|
0, 1, 5, 5, 4, 0,
|
||||||
|
1, 2, 6, 6, 5, 1,
|
||||||
|
2, 3, 7, 7, 6, 2,
|
||||||
|
3, 0, 4, 4, 7, 3,
|
||||||
|
// Arrow indices (30 indices)
|
||||||
|
8, 9, 10, // Front face
|
||||||
|
8, 10, 11, // Right face
|
||||||
|
8, 11, 12, // Back face
|
||||||
|
8, 12, 9, // Left face
|
||||||
|
9, 12, 11, 11, 10, 9 // Base of the arrow
|
||||||
|
};
|
||||||
|
|
||||||
|
auto vb = VertexBuffer::Builder()
|
||||||
|
.vertexCount(13)
|
||||||
|
.bufferCount(1)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||||
|
{ delete[] static_cast<float *>(buffer); }));
|
||||||
|
|
||||||
|
auto ib = IndexBuffer::Builder().indexCount(54).bufferType(IndexBuffer::IndexType::USHORT).build(engine);
|
||||||
|
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||||
|
indices, 54 * sizeof(uint16_t),
|
||||||
|
[](void *buffer, size_t size, void *)
|
||||||
|
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||||
|
|
||||||
|
// Create the three axes
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
_entities[i] = entityManager.create();
|
||||||
|
_materialInstances[i] = _material->createInstance();
|
||||||
|
|
||||||
|
auto baseColor = inactiveColors[i];
|
||||||
|
|
||||||
|
math::mat4f transform;
|
||||||
|
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
|
case Axis::X:
|
||||||
|
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 1.0f, 0.0f, 0.0f});
|
||||||
|
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 1.0f, 0.0f});
|
||||||
|
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// _materialInstances[i]->setParameter("axisDirection", math::float3 { 0.0f, 0.0f, 1.0f});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_materialInstances[i]->setParameter("color", baseColor);
|
||||||
|
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({{-arrowWidth, -arrowWidth, 0},
|
||||||
|
{arrowWidth, arrowWidth, lineLength + arrowLength}})
|
||||||
|
.material(0, _materialInstances[i])
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, vb, ib, 0, 54)
|
||||||
|
.priority(6)
|
||||||
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
|
.culling(false)
|
||||||
|
.receiveShadows(false)
|
||||||
|
.castShadows(false)
|
||||||
|
.build(engine, _entities[i]);
|
||||||
|
|
||||||
|
|
||||||
|
auto instance = transformManager.getInstance(_entities[i]);
|
||||||
|
transformManager.setTransform(instance, transform);
|
||||||
|
|
||||||
|
// parent the axis to the center cube
|
||||||
|
transformManager.setParent(instance, cubeTransformInstance);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
createTransparentRectangles();
|
||||||
|
}
|
||||||
|
|
||||||
|
Gizmo::~Gizmo() {
|
||||||
|
_scene->removeEntities(_entities, 7);
|
||||||
|
|
||||||
|
for(int i = 0; i < 7; i++) {
|
||||||
|
_engine.destroy(_entities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 7; i++) {
|
||||||
|
_engine.destroy(_materialInstances[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_engine.destroy(_material);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gizmo::createTransparentRectangles()
|
||||||
|
{
|
||||||
|
auto &entityManager = EntityManager::get();
|
||||||
|
auto &transformManager = _engine.getTransformManager();
|
||||||
|
|
||||||
|
float volumeWidth = 0.2f;
|
||||||
|
float volumeLength = 1.2f;
|
||||||
|
float volumeDepth = 0.2f;
|
||||||
|
|
||||||
|
float *volumeVertices = new float[8 * 3]{
|
||||||
|
-volumeWidth / 2, -volumeDepth / 2, 0,
|
||||||
|
volumeWidth / 2, -volumeDepth / 2, 0,
|
||||||
|
volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||||
|
-volumeWidth / 2, -volumeDepth / 2, volumeLength,
|
||||||
|
-volumeWidth / 2, volumeDepth / 2, 0,
|
||||||
|
volumeWidth / 2, volumeDepth / 2, 0,
|
||||||
|
volumeWidth / 2, volumeDepth / 2, volumeLength,
|
||||||
|
-volumeWidth / 2, volumeDepth / 2, volumeLength
|
||||||
|
};
|
||||||
|
|
||||||
|
uint16_t *volumeIndices = new uint16_t[36]{
|
||||||
|
0, 1, 2, 2, 3, 0, // Bottom face
|
||||||
|
4, 5, 6, 6, 7, 4, // Top face
|
||||||
|
0, 4, 7, 7, 3, 0, // Left face
|
||||||
|
1, 5, 6, 6, 2, 1, // Right face
|
||||||
|
0, 1, 5, 5, 4, 0, // Front face
|
||||||
|
3, 2, 6, 6, 7, 3 // Back face
|
||||||
|
};
|
||||||
|
|
||||||
|
auto volumeVb = VertexBuffer::Builder()
|
||||||
|
.vertexCount(8)
|
||||||
|
.bufferCount(1)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.build(_engine);
|
||||||
|
|
||||||
|
volumeVb->setBufferAt(_engine, 0, VertexBuffer::BufferDescriptor(
|
||||||
|
volumeVertices, 8 * sizeof(filament::math::float3),
|
||||||
|
[](void *buffer, size_t size, void *) { delete[] static_cast<float *>(buffer); }
|
||||||
|
));
|
||||||
|
|
||||||
|
auto volumeIb = IndexBuffer::Builder()
|
||||||
|
.indexCount(36)
|
||||||
|
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||||
|
.build(_engine);
|
||||||
|
|
||||||
|
volumeIb->setBuffer(_engine, IndexBuffer::BufferDescriptor(
|
||||||
|
volumeIndices, 36 * sizeof(uint16_t),
|
||||||
|
[](void *buffer, size_t size, void *) { delete[] static_cast<uint16_t *>(buffer); }
|
||||||
|
));
|
||||||
|
|
||||||
|
for (int i = 4; i < 7; i++)
|
||||||
|
{
|
||||||
|
_entities[i] = entityManager.create();
|
||||||
|
_materialInstances[i] = _material->createInstance();
|
||||||
|
|
||||||
|
_materialInstances[i]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 0.0f});
|
||||||
|
|
||||||
|
math::mat4f transform;
|
||||||
|
switch (i-4)
|
||||||
|
{
|
||||||
|
case Axis::X:
|
||||||
|
transform = math::mat4f::rotation(math::F_PI_2, math::float3{0, 1, 0});
|
||||||
|
break;
|
||||||
|
case Axis::Y:
|
||||||
|
transform = math::mat4f::rotation(-math::F_PI_2, math::float3{1, 0, 0});
|
||||||
|
break;
|
||||||
|
case Axis::Z:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({{-volumeWidth / 2, -volumeDepth / 2, 0}, {volumeWidth / 2, volumeDepth / 2, volumeLength}})
|
||||||
|
.material(0, _materialInstances[i])
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, volumeVb, volumeIb, 0, 36)
|
||||||
|
.priority(7)
|
||||||
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
|
.culling(false)
|
||||||
|
.receiveShadows(false)
|
||||||
|
.castShadows(false)
|
||||||
|
.build(_engine, _entities[i]);
|
||||||
|
|
||||||
|
auto instance = transformManager.getInstance(_entities[i]);
|
||||||
|
transformManager.setTransform(instance, transform);
|
||||||
|
|
||||||
|
// Parent the picking volume to the center cube
|
||||||
|
transformManager.setParent(instance, transformManager.getInstance(_entities[3]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gizmo::highlight(Entity entity) {
|
||||||
|
auto &rm = _engine.getRenderableManager();
|
||||||
|
auto renderableInstance = rm.getInstance(entity);
|
||||||
|
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||||
|
|
||||||
|
math::float4 baseColor;
|
||||||
|
if(entity == x()) {
|
||||||
|
baseColor = activeColors[Axis::X];
|
||||||
|
} else if(entity == y()) {
|
||||||
|
baseColor = activeColors[Axis::Y];
|
||||||
|
} else if(entity == z()) {
|
||||||
|
baseColor = activeColors[Axis::Z];
|
||||||
|
} else {
|
||||||
|
baseColor = math::float4 { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
|
}
|
||||||
|
|
||||||
|
materialInstance->setParameter("color", baseColor);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gizmo::unhighlight() {
|
||||||
|
auto &rm = _engine.getRenderableManager();
|
||||||
|
|
||||||
|
for(int i = 0; i < 3; i++) {
|
||||||
|
auto renderableInstance = rm.getInstance(_entities[i]);
|
||||||
|
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||||
|
|
||||||
|
math::float4 baseColor = inactiveColors[i];
|
||||||
|
materialInstance->setParameter("color", baseColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gizmo::pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y))
|
||||||
|
{
|
||||||
|
auto handler = new Gizmo::PickCallbackHandler(this, callback);
|
||||||
|
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||||
|
handler->handle(result);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Gizmo::isGizmoEntity(Entity e) {
|
||||||
|
for(int i = 0; i < 7; i++) {
|
||||||
|
if(e == _entities[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Gizmo::setVisibility(bool visible) {
|
||||||
|
if(visible) {
|
||||||
|
_scene->addEntities(_entities, 7);
|
||||||
|
} else {
|
||||||
|
_scene->removeEntities(_entities, 7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
197
thermion_dart/native/src/GridOverlay.cpp
Normal file
197
thermion_dart/native/src/GridOverlay.cpp
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
#include "GridOverlay.hpp"
|
||||||
|
|
||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <utils/Entity.h>
|
||||||
|
#include <utils/EntityManager.h>
|
||||||
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/TransformManager.h>
|
||||||
|
#include <gltfio/math.h>
|
||||||
|
|
||||||
|
#include "material/grid.h"
|
||||||
|
#include "SceneManager.hpp"
|
||||||
|
#include "Log.hpp"
|
||||||
|
|
||||||
|
namespace thermion_filament {
|
||||||
|
|
||||||
|
using namespace filament::gltfio;
|
||||||
|
|
||||||
|
GridOverlay::GridOverlay(Engine &engine) : _engine(engine)
|
||||||
|
{
|
||||||
|
auto &entityManager = EntityManager::get();
|
||||||
|
auto &transformManager = engine.getTransformManager();
|
||||||
|
|
||||||
|
const int gridSize = 100;
|
||||||
|
const float gridSpacing = 1.0f;
|
||||||
|
int vertexCount = (gridSize + 1) * 4; // 2 axes, 2 vertices per line
|
||||||
|
|
||||||
|
float* gridVertices = new float[vertexCount * 3];
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
// Create grid lines
|
||||||
|
for (int i = 0; i <= gridSize; ++i) {
|
||||||
|
float pos = i * gridSpacing - (gridSize * gridSpacing / 2);
|
||||||
|
|
||||||
|
// X-axis lines
|
||||||
|
gridVertices[index++] = pos;
|
||||||
|
gridVertices[index++] = 0;
|
||||||
|
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||||
|
|
||||||
|
gridVertices[index++] = pos;
|
||||||
|
gridVertices[index++] = 0;
|
||||||
|
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||||
|
|
||||||
|
// Z-axis lines
|
||||||
|
gridVertices[index++] = -(gridSize * gridSpacing / 2);
|
||||||
|
gridVertices[index++] = 0;
|
||||||
|
gridVertices[index++] = pos;
|
||||||
|
|
||||||
|
gridVertices[index++] = (gridSize * gridSpacing / 2);
|
||||||
|
gridVertices[index++] = 0;
|
||||||
|
gridVertices[index++] = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto vb = VertexBuffer::Builder()
|
||||||
|
.vertexCount(vertexCount)
|
||||||
|
.bufferCount(1)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(
|
||||||
|
gridVertices, vertexCount * sizeof(filament::math::float3),
|
||||||
|
[](void* buffer, size_t size, void*) { delete[] static_cast<float*>(buffer); }
|
||||||
|
));
|
||||||
|
|
||||||
|
uint32_t* gridIndices = new uint32_t[vertexCount];
|
||||||
|
for (uint32_t i = 0; i < vertexCount; ++i) {
|
||||||
|
gridIndices[i] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ib = IndexBuffer::Builder()
|
||||||
|
.indexCount(vertexCount)
|
||||||
|
.bufferType(IndexBuffer::IndexType::UINT)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||||
|
gridIndices, vertexCount * sizeof(uint32_t),
|
||||||
|
[](void* buffer, size_t size, void*) { delete[] static_cast<uint32_t*>(buffer); }
|
||||||
|
));
|
||||||
|
|
||||||
|
_gridEntity = entityManager.create();
|
||||||
|
_material = Material::Builder()
|
||||||
|
.package(GRID_PACKAGE, GRID_GRID_SIZE)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
_materialInstance = _material->createInstance();
|
||||||
|
|
||||||
|
_materialInstance->setParameter("maxDistance", 50.0f); // Adjust as needed
|
||||||
|
_materialInstance->setParameter("color", math::float3{0.5f, 0.5f, 0.5f}); // Gray color for the grid
|
||||||
|
|
||||||
|
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({{-gridSize * gridSpacing / 2, 0, -gridSize * gridSpacing / 2},
|
||||||
|
{gridSize * gridSpacing / 2, 0, gridSize * gridSpacing / 2}})
|
||||||
|
.material(0, _materialInstance)
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::LINES, vb, ib, 0, vertexCount)
|
||||||
|
.priority(6)
|
||||||
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
|
.culling(false)
|
||||||
|
.receiveShadows(false)
|
||||||
|
.castShadows(false)
|
||||||
|
.build(engine, _gridEntity);
|
||||||
|
const float sphereRadius = 0.05f;
|
||||||
|
const int sphereSegments = 16;
|
||||||
|
const int sphereRings = 16;
|
||||||
|
|
||||||
|
vertexCount = (sphereRings + 1) * (sphereSegments + 1);
|
||||||
|
int indexCount = sphereRings * sphereSegments * 6;
|
||||||
|
|
||||||
|
math::float3* vertices = new math::float3[vertexCount];
|
||||||
|
uint32_t* indices = new uint32_t[indexCount];
|
||||||
|
|
||||||
|
int vertexIndex = 0;
|
||||||
|
// Generate sphere vertices
|
||||||
|
for (int ring = 0; ring <= sphereRings; ++ring) {
|
||||||
|
float theta = ring * M_PI / sphereRings;
|
||||||
|
float sinTheta = std::sin(theta);
|
||||||
|
float cosTheta = std::cos(theta);
|
||||||
|
|
||||||
|
for (int segment = 0; segment <= sphereSegments; ++segment) {
|
||||||
|
float phi = segment * 2 * M_PI / sphereSegments;
|
||||||
|
float sinPhi = std::sin(phi);
|
||||||
|
float cosPhi = std::cos(phi);
|
||||||
|
|
||||||
|
float x = cosPhi * sinTheta;
|
||||||
|
float y = cosTheta;
|
||||||
|
float z = sinPhi * sinTheta;
|
||||||
|
|
||||||
|
vertices[vertexIndex++] = {x * sphereRadius, y * sphereRadius, z * sphereRadius};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int indexIndex = 0;
|
||||||
|
// Generate sphere indices
|
||||||
|
for (int ring = 0; ring < sphereRings; ++ring) {
|
||||||
|
for (int segment = 0; segment < sphereSegments; ++segment) {
|
||||||
|
uint32_t current = ring * (sphereSegments + 1) + segment;
|
||||||
|
uint32_t next = current + sphereSegments + 1;
|
||||||
|
|
||||||
|
indices[indexIndex++] = current;
|
||||||
|
indices[indexIndex++] = next;
|
||||||
|
indices[indexIndex++] = current + 1;
|
||||||
|
|
||||||
|
indices[indexIndex++] = current + 1;
|
||||||
|
indices[indexIndex++] = next;
|
||||||
|
indices[indexIndex++] = next + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto sphereVb = VertexBuffer::Builder()
|
||||||
|
.vertexCount(vertexCount)
|
||||||
|
.bufferCount(1)
|
||||||
|
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
sphereVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(
|
||||||
|
vertices, vertexCount * sizeof(math::float3),
|
||||||
|
[](void* buffer, size_t size, void*) { delete[] static_cast<math::float3*>(buffer); }
|
||||||
|
));
|
||||||
|
|
||||||
|
auto sphereIb = IndexBuffer::Builder()
|
||||||
|
.indexCount(indexCount)
|
||||||
|
.bufferType(IndexBuffer::IndexType::UINT)
|
||||||
|
.build(engine);
|
||||||
|
|
||||||
|
sphereIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||||
|
indices, indexCount * sizeof(uint32_t),
|
||||||
|
[](void* buffer, size_t size, void*) { delete[] static_cast<uint32_t*>(buffer); }
|
||||||
|
));
|
||||||
|
|
||||||
|
_sphereEntity = entityManager.create();
|
||||||
|
|
||||||
|
RenderableManager::Builder(1)
|
||||||
|
.boundingBox({{-sphereRadius, -sphereRadius, -sphereRadius},
|
||||||
|
{sphereRadius, sphereRadius, sphereRadius}})
|
||||||
|
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, sphereVb, sphereIb, 0, indexCount)
|
||||||
|
.priority(6)
|
||||||
|
.layerMask(0xFF, 1u << SceneManager::LAYERS::OVERLAY)
|
||||||
|
.culling(false)
|
||||||
|
.receiveShadows(false)
|
||||||
|
.castShadows(false)
|
||||||
|
.build(engine, _sphereEntity);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void GridOverlay::destroy()
|
||||||
|
{
|
||||||
|
auto &rm = _engine.getRenderableManager();
|
||||||
|
auto &tm = _engine.getTransformManager();
|
||||||
|
rm.destroy(_sphereEntity);
|
||||||
|
rm.destroy(_gridEntity);
|
||||||
|
tm.destroy(_sphereEntity);
|
||||||
|
tm.destroy(_gridEntity);
|
||||||
|
_engine.destroy(_sphereEntity);
|
||||||
|
_engine.destroy(_gridEntity);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace thermion_filament
|
||||||
184
thermion_dart/native/src/HighlightOverlay.cpp
Normal file
184
thermion_dart/native/src/HighlightOverlay.cpp
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#include <filament/Material.h>
|
||||||
|
#include <filament/MaterialInstance.h>
|
||||||
|
#include <utils/EntityManager.h>
|
||||||
|
|
||||||
|
#include "SceneManager.hpp"
|
||||||
|
|
||||||
|
namespace thermion_filament
|
||||||
|
{
|
||||||
|
|
||||||
|
SceneManager::HighlightOverlay::HighlightOverlay(
|
||||||
|
EntityId entityId,
|
||||||
|
SceneManager *const sceneManager,
|
||||||
|
Engine *engine,
|
||||||
|
float r,
|
||||||
|
float g,
|
||||||
|
float b) : _sceneManager(sceneManager), _engine(engine)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto &rm = engine->getRenderableManager();
|
||||||
|
|
||||||
|
auto &tm = engine->getTransformManager();
|
||||||
|
|
||||||
|
// Create the outline/highlight material instance
|
||||||
|
filament::gltfio::MaterialKey dummyKey; // We're not using the key for this simple material
|
||||||
|
filament::gltfio::UvMap dummyUvMap; // We're not using UV mapping for this simple material
|
||||||
|
|
||||||
|
auto materialProvider = sceneManager->unlitMaterialProvider();
|
||||||
|
|
||||||
|
_highlightMaterialInstance = materialProvider->createMaterialInstance(&dummyKey, &dummyUvMap);
|
||||||
|
_highlightMaterialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||||
|
_highlightMaterialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
|
||||||
|
_highlightMaterialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
|
||||||
|
_highlightMaterialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::NE);
|
||||||
|
_highlightMaterialInstance->setStencilReferenceValue(1);
|
||||||
|
|
||||||
|
_highlightMaterialInstance->setParameter("color", filament::math::float3{r, g, b});
|
||||||
|
_highlightMaterialInstance->setParameter("scale", 1.04f);
|
||||||
|
_highlightMaterialInstance->setCullingMode(filament::backend::CullingMode::FRONT);
|
||||||
|
|
||||||
|
|
||||||
|
auto scene = sceneManager->getScene();
|
||||||
|
|
||||||
|
_isGeometryEntity = sceneManager->isGeometryEntity(entityId);
|
||||||
|
_isGltfAsset = sceneManager->isGltfAsset(entityId);
|
||||||
|
|
||||||
|
if (!(_isGeometryEntity || _isGltfAsset))
|
||||||
|
{
|
||||||
|
Log("Failed to set stencil outline for entity %d: the entity is a child of another entity. "
|
||||||
|
"Currently, we only support outlining top-level entities."
|
||||||
|
"Call getAncestor() to get the ancestor of this entity, then set on that",
|
||||||
|
entityId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isGeometryEntity)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log("Entity %d is geometry", entityId);
|
||||||
|
|
||||||
|
auto geometryEntity = Entity::import(entityId);
|
||||||
|
auto renderable = rm.getInstance(geometryEntity);
|
||||||
|
|
||||||
|
auto materialInstance = rm.getMaterialInstanceAt(renderable, 0);
|
||||||
|
|
||||||
|
// set stencil write on the existing material
|
||||||
|
materialInstance->setStencilWrite(true);
|
||||||
|
materialInstance->setDepthWrite(true);
|
||||||
|
materialInstance->setStencilReferenceValue(1);
|
||||||
|
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||||
|
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::KEEP);
|
||||||
|
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::KEEP);
|
||||||
|
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
|
||||||
|
// materialInstance->setCullingMode(filament::MaterialInstance::CullingMode::BACK);
|
||||||
|
|
||||||
|
auto geometry = sceneManager->getGeometry(entityId);
|
||||||
|
|
||||||
|
_entity = utils::EntityManager::get().create();
|
||||||
|
RenderableManager::Builder builder(1);
|
||||||
|
builder.boundingBox(geometry->getBoundingBox())
|
||||||
|
.geometry(0, geometry->primitiveType, geometry->vertexBuffer(), geometry->indexBuffer(), 0, geometry->numIndices)
|
||||||
|
.culling(true)
|
||||||
|
.material(0, _highlightMaterialInstance)
|
||||||
|
.priority(0)
|
||||||
|
.receiveShadows(false)
|
||||||
|
.castShadows(false);
|
||||||
|
|
||||||
|
builder.build(*engine, _entity);
|
||||||
|
|
||||||
|
scene->addEntity(_entity);
|
||||||
|
auto outlineTransformInstance = tm.getInstance(_entity);
|
||||||
|
auto entityTransformInstance = tm.getInstance(geometryEntity);
|
||||||
|
tm.setParent(outlineTransformInstance, entityTransformInstance);
|
||||||
|
}
|
||||||
|
else if (_isGltfAsset)
|
||||||
|
{
|
||||||
|
Log("Entity %d is gltf", entityId);
|
||||||
|
auto *asset = sceneManager->getAssetByEntityId(entityId);
|
||||||
|
|
||||||
|
if (asset)
|
||||||
|
{
|
||||||
|
|
||||||
|
Log("Found glTF FilamentAsset with %d material instances", asset->getInstance()->getMaterialInstanceCount());
|
||||||
|
|
||||||
|
auto materialInstance = asset->getInstance()->getMaterialInstances()[0];
|
||||||
|
|
||||||
|
// set stencil write on the existing material
|
||||||
|
materialInstance->setStencilWrite(true);
|
||||||
|
materialInstance->setDepthWrite(true);
|
||||||
|
materialInstance->setStencilReferenceValue(1);
|
||||||
|
materialInstance->setStencilOpStencilFail(filament::backend::StencilOperation::KEEP);
|
||||||
|
materialInstance->setStencilOpDepthFail(filament::backend::StencilOperation::REPLACE);
|
||||||
|
materialInstance->setStencilOpDepthStencilPass(filament::backend::StencilOperation::REPLACE);
|
||||||
|
materialInstance->setStencilCompareFunction(filament::backend::SamplerCompareFunc::A);
|
||||||
|
|
||||||
|
_newInstance = sceneManager->createGltfAssetInstance(asset);
|
||||||
|
|
||||||
|
_entity = _newInstance->getRoot();
|
||||||
|
|
||||||
|
auto newTransformInstance = tm.getInstance(_entity);
|
||||||
|
|
||||||
|
auto entityTransformInstance = tm.getInstance(asset->getRoot());
|
||||||
|
tm.setParent(newTransformInstance, entityTransformInstance);
|
||||||
|
if (!_newInstance)
|
||||||
|
{
|
||||||
|
Log("Couldn't create new instance");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < _newInstance->getEntityCount(); i++)
|
||||||
|
{
|
||||||
|
auto entity = _newInstance->getEntities()[i];
|
||||||
|
auto renderableInstance = rm.getInstance(entity);
|
||||||
|
rm.setPriority(renderableInstance, 7);
|
||||||
|
if (renderableInstance.isValid())
|
||||||
|
{
|
||||||
|
for (int primitiveIndex = 0; primitiveIndex < rm.getPrimitiveCount(renderableInstance); primitiveIndex++)
|
||||||
|
{
|
||||||
|
rm.setMaterialInstanceAt(renderableInstance, primitiveIndex, _highlightMaterialInstance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("Not renderable, ignoring");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scene->addEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("Not FilamentAsset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SceneManager::HighlightOverlay::~HighlightOverlay()
|
||||||
|
{
|
||||||
|
if (_entity.isNull())
|
||||||
|
{
|
||||||
|
Log("Null entity");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_isGltfAsset)
|
||||||
|
{
|
||||||
|
_sceneManager->getScene()->removeEntities(_newInstance->getEntities(), _newInstance->getEntityCount());
|
||||||
|
_newInstance->detachMaterialInstances();
|
||||||
|
_engine->destroy(_highlightMaterialInstance);
|
||||||
|
}
|
||||||
|
else if (_isGeometryEntity)
|
||||||
|
{
|
||||||
|
auto &tm = _engine->getTransformManager();
|
||||||
|
auto transformInstance = tm.getInstance(_entity);
|
||||||
|
_sceneManager->getScene()->remove(_entity);
|
||||||
|
utils::EntityManager::get().destroy(_entity);
|
||||||
|
_engine->destroy(_entity);
|
||||||
|
_engine->destroy(_highlightMaterialInstance);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log("FATAL: Unknown highlight overlay entity type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,6 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "ResourceBuffer.hpp"
|
#include "ResourceBuffer.hpp"
|
||||||
|
|
||||||
#include "FilamentViewer.hpp"
|
#include "FilamentViewer.hpp"
|
||||||
#include "filament/LightManager.h"
|
#include "filament/LightManager.h"
|
||||||
#include "Log.hpp"
|
#include "Log.hpp"
|
||||||
@@ -13,77 +12,106 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
using namespace thermion_filament;
|
|
||||||
|
|
||||||
#ifdef __EMSCRIPTEN__
|
#ifdef __EMSCRIPTEN__
|
||||||
#include <emscripten/emscripten.h>
|
#include <emscripten/emscripten.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace thermion_filament;
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
|
||||||
#include "ThermionDartApi.h"
|
#include "ThermionDartApi.h"
|
||||||
|
|
||||||
|
// Helper function to convert filament::math::mat4 to double4x4
|
||||||
EMSCRIPTEN_KEEPALIVE const void *create_filament_viewer(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
static double4x4 convert_mat4_to_double4x4(const filament::math::mat4 &mat)
|
||||||
{
|
{
|
||||||
const auto * loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper*)loader);
|
return double4x4{
|
||||||
auto viewer = (const void *)new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
{mat[0][0], mat[0][1], mat[0][2], mat[0][3]},
|
||||||
return viewer;
|
{mat[1][0], mat[1][1], mat[1][2], mat[1][3]},
|
||||||
|
{mat[2][0], mat[2][1], mat[2][2], mat[2][3]},
|
||||||
|
{mat[3][0], mat[3][1], mat[3][2], mat[3][3]},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_render_target(const void *const viewer, intptr_t texture, uint32_t width, uint32_t height)
|
// Helper function to convert double4x4 to filament::math::mat4
|
||||||
|
static filament::math::mat4 convert_double4x4_to_mat4(const double4x4 &d_mat)
|
||||||
|
{
|
||||||
|
return filament::math::mat4{
|
||||||
|
filament::math::float4{float(d_mat.col1[0]), float(d_mat.col1[1]), float(d_mat.col1[2]), float(d_mat.col1[3])},
|
||||||
|
filament::math::float4{float(d_mat.col2[0]), float(d_mat.col2[1]), float(d_mat.col2[2]), float(d_mat.col2[3])},
|
||||||
|
filament::math::float4{float(d_mat.col3[0]), float(d_mat.col3[1]), float(d_mat.col3[2]), float(d_mat.col3[3])},
|
||||||
|
filament::math::float4{float(d_mat.col4[0]), float(d_mat.col4[1]), float(d_mat.col4[2]), float(d_mat.col4[3])}};
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TViewer *create_filament_viewer(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||||
|
{
|
||||||
|
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
|
||||||
|
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
||||||
|
return reinterpret_cast<TViewer*>(viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer) {
|
||||||
|
auto* engine = reinterpret_cast<FilamentViewer*>(viewer)->getEngine();
|
||||||
|
return reinterpret_cast<TEngine*>(engine);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_render_target(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->createRenderTarget(texture, width, height);
|
((FilamentViewer *)viewer)->createRenderTarget(texture, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer)
|
||||||
{
|
{
|
||||||
delete ((FilamentViewer *)viewer);
|
delete ((FilamentViewer *)viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_color(const void *const viewer, const float r, const float g, const float b, const float a)
|
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
|
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->clearBackgroundImage();
|
((FilamentViewer *)viewer)->clearBackgroundImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image(const void *const viewer, const char *path, bool fillHeight)
|
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight);
|
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(const void *const viewer, float x, float y, bool clamp)
|
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp);
|
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(const void *const viewer, int toneMapping)
|
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(TViewer *viewer, int toneMapping)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setToneMapping((ToneMapping)toneMapping);
|
((FilamentViewer *)viewer)->setToneMapping((ToneMapping)toneMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_bloom(const void *const viewer, float strength)
|
EMSCRIPTEN_KEEPALIVE void set_bloom(TViewer *viewer, float strength)
|
||||||
{
|
{
|
||||||
Log("Setting bloom to %f", strength);
|
|
||||||
((FilamentViewer *)viewer)->setBloom(strength);
|
((FilamentViewer *)viewer)->setBloom(strength);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_skybox(const void *const viewer, const char *skyboxPath)
|
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
|
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_ibl(const void *const viewer, const char *iblPath, float intensity)
|
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity)
|
||||||
|
{
|
||||||
|
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_ibl(TViewer *viewer, const char *iblPath, float intensity)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(const void *const viewer, float *rotationMatrix)
|
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix)
|
||||||
{
|
{
|
||||||
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
||||||
rotationMatrix[2],
|
rotationMatrix[2],
|
||||||
@@ -97,27 +125,27 @@ extern "C"
|
|||||||
((FilamentViewer *)viewer)->rotateIbl(matrix);
|
((FilamentViewer *)viewer)->rotateIbl(matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->removeSkybox();
|
((FilamentViewer *)viewer)->removeSkybox();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_ibl(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void remove_ibl(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->removeIbl();
|
((FilamentViewer *)viewer)->removeIbl();
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityId add_light(
|
EMSCRIPTEN_KEEPALIVE EntityId add_light(
|
||||||
const void *const viewer,
|
TViewer *viewer,
|
||||||
uint8_t type,
|
uint8_t type,
|
||||||
float colour,
|
float colour,
|
||||||
float intensity,
|
float intensity,
|
||||||
float posX,
|
float posX,
|
||||||
float posY,
|
float posY,
|
||||||
float posZ,
|
float posZ,
|
||||||
float dirX,
|
float dirX,
|
||||||
float dirY,
|
float dirY,
|
||||||
float dirZ,
|
float dirZ,
|
||||||
float falloffRadius,
|
float falloffRadius,
|
||||||
float spotLightConeInner,
|
float spotLightConeInner,
|
||||||
float spotLightConeOuter,
|
float spotLightConeOuter,
|
||||||
@@ -126,43 +154,37 @@ extern "C"
|
|||||||
float sunHaloFallof,
|
float sunHaloFallof,
|
||||||
bool shadows)
|
bool shadows)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->addLight(
|
return ((FilamentViewer *)viewer)->addLight((LightManager::Type)type, colour, intensity, posX, posY, posZ, dirX, dirY, dirZ, falloffRadius, spotLightConeInner, spotLightConeOuter, sunAngularRadius, sunHaloSize, sunHaloFallof, shadows);
|
||||||
(LightManager::Type)type,
|
|
||||||
colour,
|
|
||||||
intensity,
|
|
||||||
posX,
|
|
||||||
posY,
|
|
||||||
posZ,
|
|
||||||
dirX,
|
|
||||||
dirY,
|
|
||||||
dirZ,
|
|
||||||
falloffRadius,
|
|
||||||
spotLightConeInner,
|
|
||||||
spotLightConeOuter,
|
|
||||||
sunAngularRadius,
|
|
||||||
sunHaloSize,
|
|
||||||
sunHaloFallof,
|
|
||||||
shadows);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_light(const void *const viewer, int32_t entityId)
|
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, int32_t entityId, float x, float y, float z)
|
||||||
|
{
|
||||||
|
((FilamentViewer *)viewer)->setLightPosition(entityId, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, int32_t entityId, float x, float y, float z)
|
||||||
|
{
|
||||||
|
((FilamentViewer *)viewer)->setLightDirection(entityId, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_light(TViewer *viewer, int32_t entityId)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->removeLight(entityId);
|
((FilamentViewer *)viewer)->removeLight(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_lights(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void clear_lights(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->clearLights();
|
((FilamentViewer *)viewer)->clearLights();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances)
|
EMSCRIPTEN_KEEPALIVE EntityId load_glb(void *sceneManager, const char *assetPath, int numInstances, bool keepData)
|
||||||
{
|
{
|
||||||
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances);
|
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances, keepData);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length)
|
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(void *sceneManager, const void *const data, size_t length, bool keepData, int priority, int layer)
|
||||||
{
|
{
|
||||||
return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t *)data, length);
|
return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t *)data, length, 1, keepData, priority, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId create_instance(void *sceneManager, EntityId entityId)
|
EMSCRIPTEN_KEEPALIVE EntityId create_instance(void *sceneManager, EntityId entityId)
|
||||||
@@ -180,86 +202,104 @@ extern "C"
|
|||||||
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
|
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath)
|
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(void *sceneManager, const char *assetPath, const char *relativePath, bool keepData)
|
||||||
{
|
{
|
||||||
return ((SceneManager *)sceneManager)->loadGltf(assetPath, relativePath);
|
return ((SceneManager *)sceneManager)->loadGltf(assetPath, relativePath, keepData);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_main_camera(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void set_main_camera(TViewer *viewer)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->setMainCamera();
|
return ((FilamentViewer *)viewer)->setMainCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->getMainCamera();
|
return ((FilamentViewer *)viewer)->getMainCamera();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE bool set_camera(const void *const viewer, EntityId asset, const char *nodeName)
|
EMSCRIPTEN_KEEPALIVE bool set_camera(TViewer *viewer, EntityId asset, const char *nodeName)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->setCamera(asset, nodeName);
|
return ((FilamentViewer *)viewer)->setCamera(asset, nodeName);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_fov(const void *const viewer, float fovInDegrees, float aspect)
|
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->setCameraFov(double(fovInDegrees), double(aspect));
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
return cam->getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
const double *const get_camera_model_matrix(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera)
|
||||||
{
|
{
|
||||||
const auto &modelMatrix = ((FilamentViewer *)viewer)->getCameraModelMatrix();
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
double *array = (double *)calloc(16, sizeof(double));
|
return cam->getFocalLength();
|
||||||
memcpy(array, modelMatrix.asArray(), 16 * sizeof(double));
|
|
||||||
return array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const double *const get_camera_view_matrix(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal)
|
||||||
{
|
{
|
||||||
const auto &matrix = ((FilamentViewer *)viewer)->getCameraViewMatrix();
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
double *array = (double *)calloc(16, sizeof(double));
|
cam->setProjection(fovInDegrees, aspect, near, far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||||
memcpy(array, matrix.asArray(), 16 * sizeof(double));
|
|
||||||
return array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const double *const get_camera_projection_matrix(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity)
|
||||||
{
|
{
|
||||||
const auto &matrix = ((FilamentViewer *)viewer)->getCameraProjectionMatrix();
|
auto filamentCamera = ((FilamentViewer *)viewer)->getCamera(entity);
|
||||||
double *array = (double *)calloc(16, sizeof(double));
|
return reinterpret_cast<TCamera *>(filamentCamera);
|
||||||
memcpy(array, matrix.asArray(), 16 * sizeof(double));
|
|
||||||
return array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const double *const get_camera_culling_projection_matrix(const void *const viewer)
|
double4x4 get_camera_model_matrix(TCamera *camera)
|
||||||
{
|
{
|
||||||
const auto &matrix = ((FilamentViewer *)viewer)->getCameraCullingProjectionMatrix();
|
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
|
||||||
double *array = (double *)calloc(16, sizeof(double));
|
return convert_mat4_to_double4x4(mat);
|
||||||
memcpy(array, matrix.asArray(), 16 * sizeof(double));
|
|
||||||
return array;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_camera_projection_matrix(const void *const viewer, const double *const matrix, double near, double far)
|
double4x4 get_camera_view_matrix(TCamera *camera)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setCameraProjectionMatrix(matrix, near, far);
|
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
|
||||||
|
return convert_mat4_to_double4x4(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_camera_culling(const void *const viewer, double near, double far)
|
double4x4 get_camera_projection_matrix(TCamera *camera)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setCameraCulling(near, far);
|
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
|
||||||
|
return convert_mat4_to_double4x4(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
double get_camera_culling_near(const void *const viewer)
|
double4x4 get_camera_culling_projection_matrix(TCamera *camera)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->getCameraCullingNear();
|
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
|
||||||
|
return convert_mat4_to_double4x4(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
double get_camera_culling_far(const void *const viewer)
|
void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->getCameraCullingFar();
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
const auto &mat = convert_double4x4_to_mat4(matrix);
|
||||||
|
cam->setCustomProjection(mat, near, far);
|
||||||
}
|
}
|
||||||
|
|
||||||
const double *const get_camera_frustum(const void *const viewer)
|
void set_camera_lens_projection(TCamera *camera, double near, double far, double aspect, double focalLength)
|
||||||
{
|
{
|
||||||
const auto frustum = ((FilamentViewer *)viewer)->getCameraFrustum();
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
cam->setLensProjection(focalLength, aspect, near, far);
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_camera_near(TCamera *camera)
|
||||||
|
{
|
||||||
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
return cam->getNear();
|
||||||
|
}
|
||||||
|
|
||||||
|
double get_camera_culling_far(TCamera *camera)
|
||||||
|
{
|
||||||
|
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
return cam->getCullingFar();
|
||||||
|
}
|
||||||
|
|
||||||
|
const double *const get_camera_frustum(TCamera *camera)
|
||||||
|
{
|
||||||
|
|
||||||
|
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
|
||||||
|
|
||||||
const math::float4 *planes = frustum.getNormalizedPlanes();
|
const math::float4 *planes = frustum.getNormalizedPlanes();
|
||||||
double *array = (double *)calloc(24, sizeof(double));
|
double *array = (double *)calloc(24, sizeof(double));
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
@@ -274,114 +314,111 @@ extern "C"
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed)
|
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(TViewer *viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setCameraManipulatorOptions((filament::camutils::Mode)mode, orbitSpeedX, orbitSpeedY, zoomSpeed);
|
((FilamentViewer *)viewer)->setCameraManipulatorOptions((filament::camutils::Mode)mode, orbitSpeedX, orbitSpeedY, zoomSpeed);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(const void *const viewer, bool enabled)
|
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setViewFrustumCulling(enabled);
|
((FilamentViewer *)viewer)->setViewFrustumCulling(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void move_camera_to_asset(const void *const viewer, EntityId asset)
|
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->moveCameraToAsset(asset);
|
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
cam->setFocusDistance(distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(const void *const viewer, float distance)
|
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setCameraFocusDistance(distance);
|
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
cam->setExposure(aperture, shutterSpeed, sensitivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(const void *const viewer, float aperture, float shutterSpeed, float sensitivity)
|
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setCameraExposure(aperture, shutterSpeed, sensitivity);
|
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||||
|
const filament::math::mat4 &mat = convert_double4x4_to_mat4(matrix);
|
||||||
|
cam->setModelMatrix(mat);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_position(const void *const viewer, float x, float y, float z)
|
EMSCRIPTEN_KEEPALIVE bool render(
|
||||||
{
|
TViewer *viewer,
|
||||||
((FilamentViewer *)viewer)->setCameraPosition(x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_rotation(const void *const viewer, float w, float x, float y, float z)
|
|
||||||
{
|
|
||||||
((FilamentViewer *)viewer)->setCameraRotation(w, x, y, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(const void *const viewer, const float *const matrix)
|
|
||||||
{
|
|
||||||
((FilamentViewer *)viewer)->setCameraModelMatrix(matrix);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_focal_length(const void *const viewer, float focalLength)
|
|
||||||
{
|
|
||||||
((FilamentViewer *)viewer)->setCameraFocalLength(focalLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void render(
|
|
||||||
const void *const viewer,
|
|
||||||
uint64_t frameTimeInNanos,
|
uint64_t frameTimeInNanos,
|
||||||
void *pixelBuffer,
|
void *pixelBuffer,
|
||||||
void (*callback)(void *buf, size_t size, void *data),
|
void (*callback)(void *buf, size_t size, void *data),
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
|
return ((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void capture(
|
||||||
|
TViewer *viewer,
|
||||||
|
uint8_t *pixelBuffer,
|
||||||
|
void (*callback)(void))
|
||||||
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
bool useFence = true;
|
||||||
|
#else
|
||||||
|
bool useFence = false;
|
||||||
|
#endif
|
||||||
|
((FilamentViewer *)viewer)->capture(pixelBuffer, useFence, callback);
|
||||||
|
};
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
||||||
const void *const viewer,
|
TViewer *viewer,
|
||||||
float frameInterval)
|
float frameInterval)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->destroySwapChain();
|
((FilamentViewer *)viewer)->destroySwapChain();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(const void *const viewer, const void *const window, uint32_t width, uint32_t height)
|
EMSCRIPTEN_KEEPALIVE void create_swap_chain(TViewer *viewer, const void *const window, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->createSwapChain(window, width, height);
|
((FilamentViewer *)viewer)->createSwapChain(window, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void update_viewport_and_camera_projection(const void *const viewer, uint32_t width, uint32_t height, float scaleFactor)
|
EMSCRIPTEN_KEEPALIVE void update_viewport(TViewer *viewer, uint32_t width, uint32_t height)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->updateViewportAndCameraProjection(width, height, scaleFactor);
|
return ((FilamentViewer *)viewer)->updateViewport(width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void scroll_update(const void *const viewer, float x, float y, float delta)
|
EMSCRIPTEN_KEEPALIVE void scroll_update(TViewer *viewer, float x, float y, float delta)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->scrollUpdate(x, y, delta);
|
((FilamentViewer *)viewer)->scrollUpdate(x, y, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void scroll_begin(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void scroll_begin(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->scrollBegin();
|
((FilamentViewer *)viewer)->scrollBegin();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void scroll_end(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void scroll_end(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->scrollEnd();
|
((FilamentViewer *)viewer)->scrollEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void grab_begin(const void *const viewer, float x, float y, bool pan)
|
EMSCRIPTEN_KEEPALIVE void grab_begin(TViewer *viewer, float x, float y, bool pan)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->grabBegin(x, y, pan);
|
((FilamentViewer *)viewer)->grabBegin(x, y, pan);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void grab_update(const void *const viewer, float x, float y)
|
EMSCRIPTEN_KEEPALIVE void grab_update(TViewer *viewer, float x, float y)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->grabUpdate(x, y);
|
((FilamentViewer *)viewer)->grabUpdate(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void grab_end(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void grab_end(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->grabEnd();
|
((FilamentViewer *)viewer)->grabEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void *get_scene_manager(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void *get_scene_manager(TViewer *viewer)
|
||||||
{
|
{
|
||||||
return (void *)((FilamentViewer *)viewer)->getSceneManager();
|
return (void *)((FilamentViewer *)viewer)->getSceneManager();
|
||||||
}
|
}
|
||||||
@@ -418,7 +455,8 @@ extern "C"
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(void* sceneManager, EntityId asset) {
|
EMSCRIPTEN_KEEPALIVE void clear_morph_animation(void *sceneManager, EntityId asset)
|
||||||
|
{
|
||||||
((SceneManager *)sceneManager)->clearMorphAnimationBuffer(asset);
|
((SceneManager *)sceneManager)->clearMorphAnimationBuffer(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -442,40 +480,42 @@ extern "C"
|
|||||||
((SceneManager *)sceneManager)->addBoneAnimation(asset, skinIndex, boneIndex, frameData, numFrames, frameLengthInMs, fadeOutInSecs, fadeInInSecs, maxDelta);
|
((SceneManager *)sceneManager)->addBoneAnimation(asset, skinIndex, boneIndex, frameData, numFrames, frameLengthInMs, fadeOutInSecs, fadeInInSecs, maxDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(void *const viewer, bool enabled)
|
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setPostProcessing(enabled);
|
((FilamentViewer *)viewer)->setPostProcessing(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(void *const viewer, bool enabled)
|
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(TViewer *viewer, bool enabled)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setShadowsEnabled(enabled);
|
((FilamentViewer *)viewer)->setShadowsEnabled(enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_shadow_type(void *const viewer, int shadowType)
|
EMSCRIPTEN_KEEPALIVE void set_shadow_type(TViewer *viewer, int shadowType)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setShadowType((ShadowType)shadowType);
|
((FilamentViewer *)viewer)->setShadowType((ShadowType)shadowType);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(void *const viewer, float penumbraScale, float penumbraRatioScale)
|
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(TViewer *viewer, float penumbraScale, float penumbraRatioScale)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setSoftShadowOptions(penumbraScale, penumbraRatioScale);
|
((FilamentViewer *)viewer)->setSoftShadowOptions(penumbraScale, penumbraRatioScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_antialiasing(void *const viewer, bool msaa, bool fxaa, bool taa)
|
EMSCRIPTEN_KEEPALIVE void set_antialiasing(TViewer *viewer, bool msaa, bool fxaa, bool taa)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setAntiAliasing(msaa, fxaa, taa);
|
((FilamentViewer *)viewer)->setAntiAliasing(msaa, fxaa, taa);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId get_bone(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE EntityId get_bone(void *sceneManager,
|
||||||
EntityId entityId,
|
EntityId entityId,
|
||||||
int skinIndex,
|
int skinIndex,
|
||||||
int boneIndex) {
|
int boneIndex)
|
||||||
return ((SceneManager*)sceneManager)->getBone(entityId, skinIndex, boneIndex);
|
{
|
||||||
|
return ((SceneManager *)sceneManager)->getBone(entityId, skinIndex, boneIndex);
|
||||||
}
|
}
|
||||||
EMSCRIPTEN_KEEPALIVE void get_world_transform(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_world_transform(void *sceneManager,
|
||||||
EntityId entityId, float* const out) {
|
EntityId entityId, float *const out)
|
||||||
auto transform = ((SceneManager*)sceneManager)->getWorldTransform(entityId);
|
{
|
||||||
|
auto transform = ((SceneManager *)sceneManager)->getWorldTransform(entityId);
|
||||||
out[0] = transform[0][0];
|
out[0] = transform[0][0];
|
||||||
out[1] = transform[0][1];
|
out[1] = transform[0][1];
|
||||||
out[2] = transform[0][2];
|
out[2] = transform[0][2];
|
||||||
@@ -495,8 +535,9 @@ extern "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_local_transform(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_local_transform(void *sceneManager,
|
||||||
EntityId entityId, float* const out) {
|
EntityId entityId, float *const out)
|
||||||
auto transform = ((SceneManager*)sceneManager)->getLocalTransform(entityId);
|
{
|
||||||
|
auto transform = ((SceneManager *)sceneManager)->getLocalTransform(entityId);
|
||||||
out[0] = transform[0][0];
|
out[0] = transform[0][0];
|
||||||
out[1] = transform[0][1];
|
out[1] = transform[0][1];
|
||||||
out[2] = transform[0][2];
|
out[2] = transform[0][2];
|
||||||
@@ -516,26 +557,32 @@ extern "C"
|
|||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_rest_local_transforms(void *sceneManager,
|
||||||
EntityId entityId, int skinIndex, float* const out, int numBones) {
|
EntityId entityId, int skinIndex, float *const out, int numBones)
|
||||||
const auto transforms = ((SceneManager*)sceneManager)->getBoneRestTranforms(entityId, skinIndex);
|
{
|
||||||
|
const auto transforms = ((SceneManager *)sceneManager)->getBoneRestTranforms(entityId, skinIndex);
|
||||||
auto numTransforms = transforms->size();
|
auto numTransforms = transforms->size();
|
||||||
if(numTransforms != numBones) {
|
if (numTransforms != numBones)
|
||||||
|
{
|
||||||
Log("Error - %d bone transforms available but you only specified %d.", numTransforms, numBones);
|
Log("Error - %d bone transforms available but you only specified %d.", numTransforms, numBones);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for(int boneIndex = 0; boneIndex < numTransforms; boneIndex++) {
|
for (int boneIndex = 0; boneIndex < numTransforms; boneIndex++)
|
||||||
|
{
|
||||||
const auto transform = transforms->at(boneIndex);
|
const auto transform = transforms->at(boneIndex);
|
||||||
for(int colNum = 0; colNum < 4; colNum++) {
|
for (int colNum = 0; colNum < 4; colNum++)
|
||||||
for(int rowNum = 0; rowNum < 4; rowNum++) {
|
{
|
||||||
|
for (int rowNum = 0; rowNum < 4; rowNum++)
|
||||||
|
{
|
||||||
out[(boneIndex * 16) + (colNum * 4) + rowNum] = transform[colNum][rowNum];
|
out[(boneIndex * 16) + (colNum * 4) + rowNum] = transform[colNum][rowNum];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(void *sceneManager,
|
EMSCRIPTEN_KEEPALIVE void get_inverse_bind_matrix(void *sceneManager,
|
||||||
EntityId entityId, int skinIndex, int boneIndex, float* const out) {
|
EntityId entityId, int skinIndex, int boneIndex, float *const out)
|
||||||
auto transform = ((SceneManager*)sceneManager)->getInverseBindMatrix(entityId, skinIndex, boneIndex);
|
{
|
||||||
|
auto transform = ((SceneManager *)sceneManager)->getInverseBindMatrix(entityId, skinIndex, boneIndex);
|
||||||
out[0] = transform[0][0];
|
out[0] = transform[0][0];
|
||||||
out[1] = transform[0][1];
|
out[1] = transform[0][1];
|
||||||
out[2] = transform[0][2];
|
out[2] = transform[0][2];
|
||||||
@@ -586,9 +633,10 @@ extern "C"
|
|||||||
bool loop,
|
bool loop,
|
||||||
bool reverse,
|
bool reverse,
|
||||||
bool replaceActive,
|
bool replaceActive,
|
||||||
float crossfade)
|
float crossfade,
|
||||||
|
float startOffset)
|
||||||
{
|
{
|
||||||
((SceneManager *)sceneManager)->playAnimation(asset, index, loop, reverse, replaceActive, crossfade);
|
((SceneManager *)sceneManager)->playAnimation(asset, index, loop, reverse, replaceActive, crossfade, startOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame(
|
EMSCRIPTEN_KEEPALIVE void set_animation_frame(
|
||||||
@@ -624,21 +672,25 @@ extern "C"
|
|||||||
strcpy(outPtr, name.c_str());
|
strcpy(outPtr, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE int get_bone_count(void *sceneManager, EntityId assetEntity, int skinIndex) {
|
EMSCRIPTEN_KEEPALIVE int get_bone_count(void *sceneManager, EntityId assetEntity, int skinIndex)
|
||||||
|
{
|
||||||
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
|
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
|
||||||
return names->size();
|
return names->size();
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char** out, int skinIndex) {
|
EMSCRIPTEN_KEEPALIVE void get_bone_names(void *sceneManager, EntityId assetEntity, const char **out, int skinIndex)
|
||||||
|
{
|
||||||
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
|
auto names = ((SceneManager *)sceneManager)->getBoneNames(assetEntity, skinIndex);
|
||||||
for(int i = 0; i < names->size(); i++) {
|
for (int i = 0; i < names->size(); i++)
|
||||||
|
{
|
||||||
auto name_c = names->at(i).c_str();
|
auto name_c = names->at(i).c_str();
|
||||||
memcpy((void*)out[i], name_c, strlen(name_c) + 1);
|
memcpy((void *)out[i], name_c, strlen(name_c) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE bool set_transform(void* sceneManager, EntityId entityId, const float* const transform) {
|
EMSCRIPTEN_KEEPALIVE bool set_transform(void *sceneManager, EntityId entityId, const float *const transform)
|
||||||
auto matrix = math::mat4f(
|
{
|
||||||
|
auto matrix = math::mat4f(
|
||||||
transform[0], transform[1], transform[2],
|
transform[0], transform[1], transform[2],
|
||||||
transform[3],
|
transform[3],
|
||||||
transform[4],
|
transform[4],
|
||||||
@@ -653,11 +705,12 @@ extern "C"
|
|||||||
transform[13],
|
transform[13],
|
||||||
transform[14],
|
transform[14],
|
||||||
transform[15]);
|
transform[15]);
|
||||||
return ((SceneManager*)sceneManager)->setTransform(entityId, matrix);
|
return ((SceneManager *)sceneManager)->setTransform(entityId, matrix);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(void* sceneManager, EntityId entityId) {
|
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(void *sceneManager, EntityId entityId)
|
||||||
return ((SceneManager*)sceneManager)->updateBoneMatrices(entityId);
|
{
|
||||||
|
return ((SceneManager *)sceneManager)->updateBoneMatrices(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(void *sceneManager, EntityId assetEntity, EntityId childEntity)
|
EMSCRIPTEN_KEEPALIVE int get_morph_target_name_count(void *sceneManager, EntityId assetEntity, EntityId childEntity)
|
||||||
@@ -673,12 +726,12 @@ extern "C"
|
|||||||
strcpy(outPtr, name.c_str());
|
strcpy(outPtr, name.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_entity(const void *const viewer, EntityId asset)
|
EMSCRIPTEN_KEEPALIVE void remove_entity(TViewer *viewer, EntityId asset)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->removeEntity(asset);
|
((FilamentViewer *)viewer)->removeEntity(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_entities(const void *const viewer)
|
EMSCRIPTEN_KEEPALIVE void clear_entities(TViewer *viewer)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->clearEntities();
|
((FilamentViewer *)viewer)->clearEntities();
|
||||||
}
|
}
|
||||||
@@ -713,11 +766,21 @@ extern "C"
|
|||||||
((SceneManager *)sceneManager)->queuePositionUpdate(asset, x, y, z, relative);
|
((SceneManager *)sceneManager)->queuePositionUpdate(asset, x, y, z, relative);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(void *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->queueRelativePositionUpdateWorldAxis(entity, viewportX, viewportY, x, y, z);
|
||||||
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void queue_rotation_update(void *sceneManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative)
|
EMSCRIPTEN_KEEPALIVE void queue_rotation_update(void *sceneManager, EntityId asset, float rads, float x, float y, float z, float w, bool relative)
|
||||||
{
|
{
|
||||||
((SceneManager *)sceneManager)->queueRotationUpdate(asset, rads, x, y, z, w, relative);
|
((SceneManager *)sceneManager)->queueRotationUpdate(asset, rads, x, y, z, w, relative);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(void *sceneManager, EntityId entity, float viewportX, float viewportY)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(entity, viewportX, viewportY);
|
||||||
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void stop_animation(void *sceneManager, EntityId asset, int index)
|
EMSCRIPTEN_KEEPALIVE void stop_animation(void *sceneManager, EntityId asset, int index)
|
||||||
{
|
{
|
||||||
((SceneManager *)sceneManager)->stopAnimation(asset, index);
|
((SceneManager *)sceneManager)->stopAnimation(asset, index);
|
||||||
@@ -733,7 +796,7 @@ extern "C"
|
|||||||
return ((SceneManager *)sceneManager)->reveal(asset, meshName);
|
return ((SceneManager *)sceneManager)->reveal(asset, meshName);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void filament_pick(void *const viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y))
|
EMSCRIPTEN_KEEPALIVE void filament_pick(TViewer *viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y))
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->pick(static_cast<uint32_t>(x), static_cast<uint32_t>(y), callback);
|
((FilamentViewer *)viewer)->pick(static_cast<uint32_t>(x), static_cast<uint32_t>(y), callback);
|
||||||
}
|
}
|
||||||
@@ -758,12 +821,12 @@ extern "C"
|
|||||||
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
|
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_recording(void *const viewer, bool recording)
|
EMSCRIPTEN_KEEPALIVE void set_recording(TViewer *viewer, bool recording)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setRecording(recording);
|
((FilamentViewer *)viewer)->setRecording(recording);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(void *const viewer, const char *outputDirectory)
|
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(TViewer *viewer, const char *outputDirectory)
|
||||||
{
|
{
|
||||||
((FilamentViewer *)viewer)->setRecordingOutputDirectory(outputDirectory);
|
((FilamentViewer *)viewer)->setRecordingOutputDirectory(outputDirectory);
|
||||||
}
|
}
|
||||||
@@ -792,15 +855,27 @@ extern "C"
|
|||||||
{
|
{
|
||||||
return ((SceneManager *)sceneManager)->addAnimationComponent(entityId);
|
return ((SceneManager *)sceneManager)->addAnimationComponent(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_animation_component(void *const sceneManager, EntityId entityId)
|
EMSCRIPTEN_KEEPALIVE void remove_animation_component(void *const sceneManager, EntityId entityId)
|
||||||
{
|
{
|
||||||
((SceneManager *)sceneManager)->removeAnimationComponent(entityId);
|
((SceneManager *)sceneManager)->removeAnimationComponent(entityId);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId create_geometry(void *const viewer, float *vertices, int numVertices, uint16_t *indices, int numIndices, int primitiveType, const char *materialPath)
|
EMSCRIPTEN_KEEPALIVE EntityId create_geometry(
|
||||||
|
void *const sceneManager,
|
||||||
|
float *vertices,
|
||||||
|
int numVertices,
|
||||||
|
float *normals,
|
||||||
|
int numNormals,
|
||||||
|
float *uvs,
|
||||||
|
int numUvs,
|
||||||
|
uint16_t *indices,
|
||||||
|
int numIndices,
|
||||||
|
int primitiveType,
|
||||||
|
TMaterialInstance *materialInstance,
|
||||||
|
bool keepData)
|
||||||
{
|
{
|
||||||
return ((FilamentViewer *)viewer)->createGeometry(vertices, (uint32_t)numVertices, indices, numIndices, (filament::RenderableManager::PrimitiveType)primitiveType, materialPath);
|
return ((SceneManager *)sceneManager)->createGeometry(vertices, (uint32_t)numVertices, normals, (uint32_t)numNormals, uvs, numUvs, indices, numIndices, (filament::RenderableManager::PrimitiveType)primitiveType, reinterpret_cast<MaterialInstance *>(materialInstance), keepData);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char *name)
|
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(void *const sceneManager, const EntityId parent, const char *name)
|
||||||
@@ -814,9 +889,14 @@ extern "C"
|
|||||||
return ((SceneManager *)sceneManager)->getParent(child);
|
return ((SceneManager *)sceneManager)->getParent(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_parent(void *const sceneManager, EntityId child, EntityId parent)
|
EMSCRIPTEN_KEEPALIVE EntityId get_ancestor(void *const sceneManager, EntityId child)
|
||||||
{
|
{
|
||||||
((SceneManager *)sceneManager)->setParent(child, parent);
|
return ((SceneManager *)sceneManager)->getAncestor(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_parent(void *const sceneManager, EntityId child, EntityId parent, bool preserveScaling)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->setParent(child, parent, preserveScaling);
|
||||||
}
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void test_collisions(void *const sceneManager, EntityId entity)
|
EMSCRIPTEN_KEEPALIVE void test_collisions(void *const sceneManager, EntityId entity)
|
||||||
@@ -831,6 +911,166 @@ extern "C"
|
|||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_gizmo(void *const sceneManager, EntityId *out)
|
EMSCRIPTEN_KEEPALIVE void get_gizmo(void *const sceneManager, EntityId *out)
|
||||||
{
|
{
|
||||||
return ((SceneManager *)sceneManager)->getGizmo(out);
|
auto gizmo = ((SceneManager *)sceneManager)->gizmo;
|
||||||
|
out[0] = Entity::smuggle(gizmo->x());
|
||||||
|
out[1] = Entity::smuggle(gizmo->y());
|
||||||
|
out[2] = Entity::smuggle(gizmo->z());
|
||||||
|
out[3] = Entity::smuggle(gizmo->center());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(void *const sceneManager, EntityId entity)
|
||||||
|
{
|
||||||
|
return ((SceneManager *)sceneManager)->getBoundingBox(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(void *const sceneManager, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
|
||||||
|
{
|
||||||
|
auto box = ((SceneManager *)sceneManager)->getBoundingBox(entity);
|
||||||
|
*minX = box.minX;
|
||||||
|
*minY = box.minY;
|
||||||
|
*maxX = box.maxX;
|
||||||
|
*maxY = box.maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_visibility_layer(void *const sceneManager, EntityId entity, int layer) {
|
||||||
|
((SceneManager*)sceneManager)->setVisibilityLayer(entity, layer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_layer_visibility(void *const sceneManager, int layer, bool visible)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->setLayerVisibility((SceneManager::LAYERS)layer, visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void pick_gizmo(void *const sceneManager, int x, int y, void (*callback)(EntityId entityId, int x, int y))
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->gizmo->pick(x, y, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_gizmo_visibility(void *const sceneManager, bool visible)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->gizmo->setVisibility(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(void *const sceneManager, EntityId entityId, float r, float g, float b)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->setStencilHighlight(entityId, r, g, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(void *const sceneManager, EntityId entityId)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->removeStencilHighlight(entityId);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_property_float(void *const sceneManager, EntityId entity, int materialIndex, const char *property, float value)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TMaterialInstance* get_material_instance_at(void *const sceneManager, EntityId entity, int materialIndex) {
|
||||||
|
auto instance = ((SceneManager *)sceneManager)->getMaterialInstanceAt(entity, materialIndex);
|
||||||
|
return reinterpret_cast<TMaterialInstance*>(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_property_int(void *const sceneManager, EntityId entity, int materialIndex, const char *property, int32_t value)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(void *const sceneManager, EntityId entity, int materialIndex, const char *property, double4 value)
|
||||||
|
{
|
||||||
|
filament::math::float4 filamentValue;
|
||||||
|
filamentValue.x = static_cast<float32_t>(value.x);
|
||||||
|
filamentValue.y = static_cast<float32_t>(value.y);
|
||||||
|
filamentValue.z = static_cast<float32_t>(value.z);
|
||||||
|
filamentValue.w = static_cast<float32_t>(value.w);
|
||||||
|
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, filamentValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||||
|
{
|
||||||
|
((FilamentViewer *)viewer)->unprojectTexture(entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void *const create_texture(void *const sceneManager, uint8_t *data, size_t length)
|
||||||
|
{
|
||||||
|
return (void *const)((SceneManager *)sceneManager)->createTexture(data, length, "SOMETEXTURE");
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void apply_texture_to_material(void *const sceneManager, EntityId entity, void *const texture, const char *parameterName, int materialIndex)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->applyTexture(entity, reinterpret_cast<Texture *>(texture), parameterName, materialIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_texture(void *const sceneManager, void *const texture)
|
||||||
|
{
|
||||||
|
((SceneManager *)sceneManager)->destroyTexture(reinterpret_cast<Texture *>(texture));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TMaterialInstance* create_material_instance(void *const sceneManager, TMaterialKey materialConfig)
|
||||||
|
{
|
||||||
|
|
||||||
|
filament::gltfio::MaterialKey config;
|
||||||
|
memset(&config, 0, sizeof(MaterialKey));
|
||||||
|
|
||||||
|
// Set and log each field
|
||||||
|
config.unlit = materialConfig.unlit;
|
||||||
|
config.doubleSided = materialConfig.doubleSided;
|
||||||
|
config.useSpecularGlossiness = materialConfig.useSpecularGlossiness;
|
||||||
|
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig.alphaMode);
|
||||||
|
config.hasBaseColorTexture = materialConfig.hasBaseColorTexture;
|
||||||
|
config.hasClearCoat = materialConfig.hasClearCoat;
|
||||||
|
config.hasClearCoatNormalTexture = materialConfig.hasClearCoatNormalTexture;
|
||||||
|
config.hasClearCoatRoughnessTexture = materialConfig.hasClearCoatRoughnessTexture;
|
||||||
|
config.hasEmissiveTexture = materialConfig.hasEmissiveTexture;
|
||||||
|
config.hasIOR = materialConfig.hasIOR;
|
||||||
|
config.hasMetallicRoughnessTexture = materialConfig.hasMetallicRoughnessTexture;
|
||||||
|
config.hasNormalTexture = materialConfig.hasNormalTexture;
|
||||||
|
config.hasOcclusionTexture = materialConfig.hasOcclusionTexture;
|
||||||
|
config.hasSheen = materialConfig.hasSheen;
|
||||||
|
config.hasSheenColorTexture = materialConfig.hasSheenColorTexture;
|
||||||
|
config.hasSheenRoughnessTexture = materialConfig.hasSheenRoughnessTexture;
|
||||||
|
config.hasTextureTransforms = materialConfig.hasTextureTransforms;
|
||||||
|
config.hasTransmission = materialConfig.hasTransmission;
|
||||||
|
config.hasTransmissionTexture = materialConfig.hasTransmissionTexture;
|
||||||
|
config.hasVolume = materialConfig.hasVolume;
|
||||||
|
config.hasVolumeThicknessTexture = materialConfig.hasVolumeThicknessTexture;
|
||||||
|
config.baseColorUV = materialConfig.baseColorUV;
|
||||||
|
config.hasVertexColors = materialConfig.hasVertexColors;
|
||||||
|
auto materialInstance = ((SceneManager *)sceneManager)->createUbershaderMaterialInstance(config);
|
||||||
|
return reinterpret_cast<TMaterialInstance*>(materialInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_unlit_material_instance(void *const sceneManager) {
|
||||||
|
auto * instance = ((SceneManager*)sceneManager)->createUnlitMaterialInstance();
|
||||||
|
return reinterpret_cast<TMaterialInstance*>(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_material_instance(void *const sceneManager, TMaterialInstance *instance) {
|
||||||
|
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance*>(instance));
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* materialInstance, bool enabled) {
|
||||||
|
reinterpret_cast<MaterialInstance*>(materialInstance)->setDepthWrite(enabled);
|
||||||
|
}
|
||||||
|
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled) {
|
||||||
|
reinterpret_cast<MaterialInstance*>(materialInstance)->setDepthCulling(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* tCamera, double4x4 projectionMatrix, double near, double far) {
|
||||||
|
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||||
|
camera->setCustomProjection(convert_double4x4_to_mat4(projectionMatrix), near, far);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId) {
|
||||||
|
auto * engine = reinterpret_cast<Engine*>(tEngine);
|
||||||
|
auto * camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
||||||
|
return reinterpret_cast<TCamera*>(camera);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,885 +0,0 @@
|
|||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
#define GL_GLEXT_PROTOTYPES
|
|
||||||
#include <GL/gl.h>
|
|
||||||
#include <GL/glext.h>
|
|
||||||
|
|
||||||
#include <emscripten/emscripten.h>
|
|
||||||
#include <emscripten/bind.h>
|
|
||||||
#include <emscripten/html5.h>
|
|
||||||
#include <emscripten/threading.h>
|
|
||||||
#include <emscripten/val.h>
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "ThermionDartFFIApi.h"
|
|
||||||
#include "FilamentViewer.hpp"
|
|
||||||
#include "Log.hpp"
|
|
||||||
#include "ThreadPool.hpp"
|
|
||||||
#include "filament/LightManager.h"
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
using namespace thermion_filament;
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
class RenderLoop
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
explicit RenderLoop()
|
|
||||||
{
|
|
||||||
srand(time(NULL));
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
pthread_attr_t attr;
|
|
||||||
pthread_attr_init(&attr);
|
|
||||||
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
|
|
||||||
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
|
|
||||||
#else
|
|
||||||
t = new std::thread([this]() {
|
|
||||||
start();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
~RenderLoop()
|
|
||||||
{
|
|
||||||
_stop = true;
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
pthread_join(t, NULL);
|
|
||||||
#else
|
|
||||||
t->join();
|
|
||||||
#endif
|
|
||||||
Log("Render loop killed");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mainLoop(void* arg) {
|
|
||||||
((RenderLoop*)arg)->iter();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *startHelper(void * parm) {
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
emscripten_set_main_loop_arg(&RenderLoop::mainLoop, parm, 0, true);
|
|
||||||
#else
|
|
||||||
((RenderLoop*)parm)->start();
|
|
||||||
#endif
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void start() {
|
|
||||||
while (!_stop) {
|
|
||||||
iter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void iter() {
|
|
||||||
|
|
||||||
auto frameStart = std::chrono::high_resolution_clock::now();
|
|
||||||
if (_rendering) {
|
|
||||||
doRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto now = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now - frameStart).count();
|
|
||||||
|
|
||||||
std::function<void()> task;
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> lock(_access);
|
|
||||||
while(true) {
|
|
||||||
now = std::chrono::high_resolution_clock::now();
|
|
||||||
elapsed = std::chrono::duration_cast<std::chrono::microseconds>(now - frameStart).count();
|
|
||||||
if(elapsed >= _frameIntervalInMicroseconds) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(!_tasks.empty()) {
|
|
||||||
task = std::move(_tasks.front());
|
|
||||||
_tasks.pop_front();
|
|
||||||
task();
|
|
||||||
} else {
|
|
||||||
_cond.wait_for(lock, std::chrono::duration<float, std::milli>(1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void createViewer(void *const context,
|
|
||||||
void *const platform,
|
|
||||||
const char *uberArchivePath,
|
|
||||||
const ResourceLoaderWrapper *const loader,
|
|
||||||
void (*renderCallback)(void *),
|
|
||||||
void *const owner,
|
|
||||||
void (*callback)(void *const))
|
|
||||||
{
|
|
||||||
_renderCallback = renderCallback;
|
|
||||||
_renderCallbackOwner = owner;
|
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
|
||||||
{
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
_context = thermion_dart_web_create_gl_context();
|
|
||||||
|
|
||||||
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
|
|
||||||
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
|
|
||||||
std::cout << "Failed to make context current." << std::endl;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
glClearColor(0.0, 0.5, 0.5, 1.0);
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
// emscripten_webgl_commit_frame();
|
|
||||||
|
|
||||||
_viewer = (FilamentViewer*) create_filament_viewer((void* const) _context, loader, platform, uberArchivePath);
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
|
||||||
}, callback, _viewer);
|
|
||||||
#else
|
|
||||||
_viewer = (FilamentViewer*)create_filament_viewer(context, loader, platform, uberArchivePath);
|
|
||||||
callback(_viewer);
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroyViewer(FilamentViewer* viewer)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]() mutable {
|
|
||||||
_rendering = false;
|
|
||||||
_viewer = nullptr;
|
|
||||||
destroy_filament_viewer(viewer);
|
|
||||||
});
|
|
||||||
auto fut = add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setRendering(bool rendering, void(*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]() mutable
|
|
||||||
{
|
|
||||||
this->_rendering = rendering;
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
void doRender()
|
|
||||||
{
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
if(emscripten_is_webgl_context_lost(_context) == EM_TRUE) {
|
|
||||||
Log("Context lost");
|
|
||||||
auto sleepFor = std::chrono::seconds(1);
|
|
||||||
std::this_thread::sleep_for(sleepFor);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
render(_viewer, 0, nullptr, nullptr, nullptr);
|
|
||||||
if (_renderCallback)
|
|
||||||
{
|
|
||||||
_renderCallback(_renderCallbackOwner);
|
|
||||||
}
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
// emscripten_webgl_commit_frame();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
|
||||||
{
|
|
||||||
_frameIntervalInMicroseconds = static_cast<int>(1000.0f * frameIntervalInMilliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Rt>
|
|
||||||
auto add_task(std::packaged_task<Rt()> &pt) -> std::future<Rt>
|
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(_access);
|
|
||||||
auto ret = pt.get_future();
|
|
||||||
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
|
|
||||||
std::move(pt))]
|
|
||||||
{ (*pt)(); });
|
|
||||||
_cond.notify_one();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool _stop = false;
|
|
||||||
bool _rendering = false;
|
|
||||||
int _frameIntervalInMicroseconds = 1000000.0 / 60.0;
|
|
||||||
std::mutex _access;
|
|
||||||
void (*_renderCallback)(void *const) = nullptr;
|
|
||||||
void *_renderCallbackOwner = nullptr;
|
|
||||||
|
|
||||||
|
|
||||||
std::condition_variable _cond;
|
|
||||||
std::deque<std::function<void()>> _tasks;
|
|
||||||
FilamentViewer* _viewer = nullptr;
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
pthread_t t;
|
|
||||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
|
|
||||||
int _frameNum = 0;
|
|
||||||
#else
|
|
||||||
std::thread *t = nullptr;
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
static RenderLoop *_rl;
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_ffi(
|
|
||||||
void *const context, void *const platform, const char *uberArchivePath,
|
|
||||||
const void *const loader,
|
|
||||||
void (*renderCallback)(void *const renderCallbackOwner),
|
|
||||||
void *const renderCallbackOwner,
|
|
||||||
void (*callback)(void *const))
|
|
||||||
{
|
|
||||||
|
|
||||||
if (!_rl)
|
|
||||||
{
|
|
||||||
_rl = new RenderLoop();
|
|
||||||
}
|
|
||||||
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapper *const)loader,
|
|
||||||
renderCallback, renderCallbackOwner, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer)
|
|
||||||
{
|
|
||||||
_rl->destroyViewer((FilamentViewer*)viewer);
|
|
||||||
delete _rl;
|
|
||||||
_rl = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer,
|
|
||||||
void *const surface,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height,
|
|
||||||
void (*onComplete)())
|
|
||||||
{
|
|
||||||
Log("Creating swapchain %dx%d with viewer %lu & surface %lu", width, height, viewer, surface);
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]() mutable
|
|
||||||
{
|
|
||||||
create_swap_chain(viewer, surface, width, height);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, onComplete);
|
|
||||||
#else
|
|
||||||
onComplete();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_ffi(void *const viewer, void (*onComplete)())
|
|
||||||
{
|
|
||||||
Log("Destroying swapchain");
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]() mutable
|
|
||||||
{
|
|
||||||
destroy_swap_chain(viewer);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, onComplete);
|
|
||||||
#else
|
|
||||||
onComplete();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_render_target_ffi(void *const viewer,
|
|
||||||
intptr_t nativeTextureId,
|
|
||||||
uint32_t width,
|
|
||||||
uint32_t height,
|
|
||||||
void (*onComplete)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
|
||||||
{
|
|
||||||
create_render_target(viewer, nativeTextureId, width, height);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, onComplete);
|
|
||||||
#else
|
|
||||||
onComplete();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void update_viewport_and_camera_projection_ffi(
|
|
||||||
void *const viewer, const uint32_t width, const uint32_t height,
|
|
||||||
const float scaleFactor,
|
|
||||||
void (*onComplete)())
|
|
||||||
{
|
|
||||||
Log("Update viewport %dx%d", width, height);
|
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
|
||||||
{
|
|
||||||
update_viewport_and_camera_projection(viewer, width, height, scaleFactor);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, onComplete);
|
|
||||||
#else
|
|
||||||
onComplete();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_rendering_ffi(void *const viewer,
|
|
||||||
bool rendering, void (*callback)())
|
|
||||||
{
|
|
||||||
if (!_rl)
|
|
||||||
{
|
|
||||||
Log("No render loop!"); // PANIC?
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_rl->setRendering(rendering, callback);
|
|
||||||
if (rendering)
|
|
||||||
{
|
|
||||||
Log("Set rendering to true");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Log("Set rendering to false");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void
|
|
||||||
set_frame_interval_ffi(void* const viewer, float frameIntervalInMilliseconds)
|
|
||||||
{
|
|
||||||
_rl->setFrameIntervalInMilliseconds(frameIntervalInMilliseconds);
|
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
|
||||||
{ ((FilamentViewer*)viewer)->setFrameInterval(frameIntervalInMilliseconds); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void render_ffi(void *const viewer)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]() mutable
|
|
||||||
{ _rl->doRender(); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void
|
|
||||||
set_background_color_ffi(void *const viewer, const float r, const float g,
|
|
||||||
const float b, const float a)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]() mutable
|
|
||||||
{ set_background_color(viewer, r, g, b, a); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_gltf_ffi(void *const sceneManager,
|
|
||||||
const char *path,
|
|
||||||
const char *relativeResourcePath,
|
|
||||||
void (*callback)(EntityId))
|
|
||||||
{
|
|
||||||
std::packaged_task<EntityId()> lambda([=]() mutable
|
|
||||||
{
|
|
||||||
auto entity = load_gltf(sceneManager, path, relativeResourcePath);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
|
||||||
}, callback, entity);
|
|
||||||
#else
|
|
||||||
callback(entity);
|
|
||||||
#endif
|
|
||||||
return entity; });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_glb_ffi(void *const sceneManager,
|
|
||||||
const char *path, int numInstances, void (*callback)(EntityId))
|
|
||||||
{
|
|
||||||
std::packaged_task<EntityId()> lambda(
|
|
||||||
[=]() mutable
|
|
||||||
{
|
|
||||||
auto entity = load_glb(sceneManager, path, numInstances);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
|
||||||
}, callback, entity);
|
|
||||||
#else
|
|
||||||
callback(entity);
|
|
||||||
#endif
|
|
||||||
return entity;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_ffi(void *const sceneManager,
|
|
||||||
const void *const data, size_t length, int numInstances, void (*callback)(EntityId))
|
|
||||||
{
|
|
||||||
std::packaged_task<EntityId()> lambda(
|
|
||||||
[=]() mutable
|
|
||||||
{
|
|
||||||
auto entity = load_glb_from_buffer(sceneManager, data, length);
|
|
||||||
callback(entity);
|
|
||||||
return entity;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_background_image_ffi(void *const viewer)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ clear_background_image(viewer); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image_ffi(void *const viewer,
|
|
||||||
const char *path,
|
|
||||||
bool fillHeight, void (*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
set_background_image(viewer, path, fillHeight);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_ffi(void *const viewer,
|
|
||||||
float x, float y,
|
|
||||||
bool clamp)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{ set_background_image_position(viewer, x, y, clamp); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_ffi(void *const viewer,
|
|
||||||
int toneMapping)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{ set_tone_mapping(viewer, toneMapping); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_bloom_ffi(void *const viewer, float strength)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ set_bloom(viewer, strength); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_skybox_ffi(void *const viewer,
|
|
||||||
const char *skyboxPath,
|
|
||||||
void (*onComplete)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{
|
|
||||||
load_skybox(viewer, skyboxPath);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, onComplete);
|
|
||||||
#else
|
|
||||||
onComplete();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void load_ibl_ffi(void *const viewer, const char *iblPath,
|
|
||||||
float intensity)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{ load_ibl(viewer, iblPath, intensity); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_ffi(void *const viewer)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ remove_skybox(viewer); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_ibl_ffi(void *const viewer)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ remove_ibl(viewer); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
void add_light_ffi(
|
|
||||||
void *const viewer,
|
|
||||||
uint8_t type,
|
|
||||||
float colour,
|
|
||||||
float intensity,
|
|
||||||
float posX,
|
|
||||||
float posY,
|
|
||||||
float posZ,
|
|
||||||
float dirX,
|
|
||||||
float dirY,
|
|
||||||
float dirZ,
|
|
||||||
float falloffRadius,
|
|
||||||
float spotLightConeInner,
|
|
||||||
float spotLightConeOuter,
|
|
||||||
float sunAngularRadius,
|
|
||||||
float sunHaloSize,
|
|
||||||
float sunHaloFallof,
|
|
||||||
bool shadows,
|
|
||||||
void (*callback)(EntityId))
|
|
||||||
{
|
|
||||||
std::packaged_task<EntityId()> lambda([=]
|
|
||||||
{
|
|
||||||
auto entity = add_light(
|
|
||||||
viewer,
|
|
||||||
type,
|
|
||||||
colour,
|
|
||||||
intensity,
|
|
||||||
posX,
|
|
||||||
posY,
|
|
||||||
posZ,
|
|
||||||
dirX,
|
|
||||||
dirY,
|
|
||||||
dirZ,
|
|
||||||
falloffRadius,
|
|
||||||
spotLightConeInner,
|
|
||||||
spotLightConeOuter,
|
|
||||||
sunAngularRadius,
|
|
||||||
sunHaloSize,
|
|
||||||
sunHaloFallof,
|
|
||||||
shadows);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
|
||||||
}, callback, entity);
|
|
||||||
#else
|
|
||||||
callback(entity);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return entity; });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_light_ffi(void *const viewer,
|
|
||||||
EntityId entityId)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ remove_light(viewer, entityId); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_lights_ffi(void *const viewer)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ clear_lights(viewer); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void remove_entity_ffi(void *const viewer,
|
|
||||||
EntityId asset, void (*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{
|
|
||||||
remove_entity(viewer, asset);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void clear_entities_ffi(void *const viewer, void (*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{
|
|
||||||
clear_entities(viewer);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_ffi(void *const viewer, EntityId asset,
|
|
||||||
const char *nodeName, void (*callback)(bool))
|
|
||||||
{
|
|
||||||
std::packaged_task<bool()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto success = set_camera(viewer, asset, nodeName);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, success);
|
|
||||||
#else
|
|
||||||
callback(success);
|
|
||||||
#endif
|
|
||||||
return success;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void
|
|
||||||
get_morph_target_name_ffi(void *sceneManager, EntityId assetEntity,
|
|
||||||
EntityId childEntity, char *const outPtr, int index, void (*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{
|
|
||||||
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void
|
|
||||||
get_morph_target_name_count_ffi(void *sceneManager, EntityId assetEntity,
|
|
||||||
EntityId childEntity, void (*callback)(int))
|
|
||||||
{
|
|
||||||
std::packaged_task<int()> lambda([=]
|
|
||||||
{
|
|
||||||
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, count);
|
|
||||||
#else
|
|
||||||
callback(count);
|
|
||||||
#endif
|
|
||||||
return count; });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void play_animation_ffi(void *const sceneManager,
|
|
||||||
EntityId asset, int index,
|
|
||||||
bool loop, bool reverse,
|
|
||||||
bool replaceActive,
|
|
||||||
float crossfade)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ play_animation(sceneManager, asset, index, loop, reverse, replaceActive,
|
|
||||||
crossfade); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_animation_frame_ffi(void *const sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
int animationIndex,
|
|
||||||
int animationFrame)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda([=]
|
|
||||||
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void stop_animation_ffi(void *const sceneManager,
|
|
||||||
EntityId asset, int index)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{ stop_animation(sceneManager, asset, index); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_animation_count_ffi(void *const sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
void (*callback)(int))
|
|
||||||
{
|
|
||||||
std::packaged_task<int()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto count = get_animation_count(sceneManager, asset);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, count);
|
|
||||||
#else
|
|
||||||
callback(count);
|
|
||||||
#endif
|
|
||||||
return count;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void get_animation_name_ffi(void *const sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
char *const outPtr,
|
|
||||||
int index,
|
|
||||||
void (*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
get_animation_name(sceneManager, asset, outPtr, index);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_post_processing_ffi(void *const viewer,
|
|
||||||
bool enabled)
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{ set_post_processing(viewer, enabled); });
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void
|
|
||||||
get_name_for_entity_ffi(void *const sceneManager, const EntityId entityId, void (*callback)(const char *))
|
|
||||||
{
|
|
||||||
std::packaged_task<const char *()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto name = get_name_for_entity(sceneManager, entityId);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, name);
|
|
||||||
#else
|
|
||||||
callback(name);
|
|
||||||
#endif
|
|
||||||
return name;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_morph_target_weights_ffi(void *const sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
const float *const morphData,
|
|
||||||
int numWeights,
|
|
||||||
void (*callback)(bool))
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, result);
|
|
||||||
#else
|
|
||||||
callback(result);
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void set_bone_transform_ffi(
|
|
||||||
void *sceneManager,
|
|
||||||
EntityId asset,
|
|
||||||
int skinIndex,
|
|
||||||
int boneIndex,
|
|
||||||
const float *const transform,
|
|
||||||
void (*callback)(bool))
|
|
||||||
{
|
|
||||||
std::packaged_task<bool()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, success);
|
|
||||||
#else
|
|
||||||
callback(success);
|
|
||||||
#endif
|
|
||||||
return success;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_ffi(void *sceneManager,
|
|
||||||
EntityId entity, void(*callback)(bool)) {
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto success = update_bone_matrices(sceneManager, entity);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback, success);
|
|
||||||
#else
|
|
||||||
callback(success);
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_ffi(void *const sceneManager, EntityId entityId, void(*callback)())
|
|
||||||
{
|
|
||||||
std::packaged_task<void()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
reset_to_rest_pose(sceneManager, entityId);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0);
|
|
||||||
}, callback);
|
|
||||||
#else
|
|
||||||
callback();
|
|
||||||
#endif
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE void create_geometry_ffi(
|
|
||||||
void *const viewer,
|
|
||||||
float *vertices,
|
|
||||||
int numVertices,
|
|
||||||
uint16_t *indices,
|
|
||||||
int numIndices,
|
|
||||||
int primitiveType,
|
|
||||||
const char *materialPath,
|
|
||||||
void (*callback)(EntityId))
|
|
||||||
{
|
|
||||||
std::packaged_task<EntityId()> lambda(
|
|
||||||
[=]
|
|
||||||
{
|
|
||||||
auto entity = create_geometry(viewer, vertices, numVertices, indices, numIndices, primitiveType, materialPath);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
MAIN_THREAD_EM_ASM({
|
|
||||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
|
||||||
}, callback, entity);
|
|
||||||
#else
|
|
||||||
callback(entity);
|
|
||||||
#endif
|
|
||||||
return entity;
|
|
||||||
});
|
|
||||||
auto fut = _rl->add_task(lambda);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
848
thermion_dart/native/src/ThermionDartRenderThreadApi.cpp
Normal file
848
thermion_dart/native/src/ThermionDartRenderThreadApi.cpp
Normal file
@@ -0,0 +1,848 @@
|
|||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
#define GL_GLEXT_PROTOTYPES
|
||||||
|
#include <GL/gl.h>
|
||||||
|
#include <GL/glext.h>
|
||||||
|
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
#include <emscripten/bind.h>
|
||||||
|
#include <emscripten/html5.h>
|
||||||
|
#include <emscripten/threading.h>
|
||||||
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ThermionDartRenderThreadApi.h"
|
||||||
|
#include "FilamentViewer.hpp"
|
||||||
|
#include "Log.hpp"
|
||||||
|
#include "ThreadPool.hpp"
|
||||||
|
#include "filament/LightManager.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <mutex>
|
||||||
|
#include <thread>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
using namespace thermion_filament;
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
class RenderLoop
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit RenderLoop()
|
||||||
|
{
|
||||||
|
srand(time(NULL));
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
pthread_attr_t attr;
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
|
||||||
|
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
|
||||||
|
#else
|
||||||
|
t = new std::thread([this]()
|
||||||
|
{ start(); });
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
~RenderLoop()
|
||||||
|
{
|
||||||
|
_render = false;
|
||||||
|
_stop = true;
|
||||||
|
_cv.notify_one();
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
pthread_join(t, NULL);
|
||||||
|
#else
|
||||||
|
t->join();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mainLoop(void *arg)
|
||||||
|
{
|
||||||
|
((RenderLoop *)arg)->iter();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *startHelper(void *parm)
|
||||||
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
emscripten_set_main_loop_arg(&RenderLoop::mainLoop, parm, 0, true);
|
||||||
|
#else
|
||||||
|
((RenderLoop *)parm)->start();
|
||||||
|
#endif
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void start()
|
||||||
|
{
|
||||||
|
while (!_stop)
|
||||||
|
{
|
||||||
|
iter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void requestFrame()
|
||||||
|
{
|
||||||
|
this->_render = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iter()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
if (_render)
|
||||||
|
{
|
||||||
|
doRender();
|
||||||
|
_render = false;
|
||||||
|
|
||||||
|
// Calculate and print FPS
|
||||||
|
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||||
|
float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - _lastFrameTime).count();
|
||||||
|
_lastFrameTime = currentTime;
|
||||||
|
|
||||||
|
_frameCount++;
|
||||||
|
_accumulatedTime += deltaTime;
|
||||||
|
|
||||||
|
if (_accumulatedTime >= 1.0f) // Update FPS every second
|
||||||
|
{
|
||||||
|
_fps = _frameCount / _accumulatedTime;
|
||||||
|
std::cout << "FPS: " << _fps << std::endl;
|
||||||
|
_frameCount = 0;
|
||||||
|
_accumulatedTime = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!_tasks.empty())
|
||||||
|
{
|
||||||
|
auto task = std::move(_tasks.front());
|
||||||
|
_tasks.pop_front();
|
||||||
|
lock.unlock();
|
||||||
|
task();
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
_cv.wait_for(lock, std::chrono::microseconds(1000), [this]
|
||||||
|
{ return !_tasks.empty() || _stop || _render; });
|
||||||
|
|
||||||
|
if (_stop)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void createViewer(void *const context,
|
||||||
|
void *const platform,
|
||||||
|
const char *uberArchivePath,
|
||||||
|
const ResourceLoaderWrapper *const loader,
|
||||||
|
void (*renderCallback)(void *),
|
||||||
|
void *const owner,
|
||||||
|
void (*callback)(TViewer*))
|
||||||
|
{
|
||||||
|
_renderCallback = renderCallback;
|
||||||
|
_renderCallbackOwner = owner;
|
||||||
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
_context = thermion_dart_web_create_gl_context();
|
||||||
|
|
||||||
|
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
|
||||||
|
if (success != EMSCRIPTEN_RESULT_SUCCESS)
|
||||||
|
{
|
||||||
|
std::cout << "Failed to make context current." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
glClearColor(0.0, 0.5, 0.5, 1.0);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
// emscripten_webgl_commit_frame();
|
||||||
|
|
||||||
|
_viewer = (FilamentViewer *)create_filament_viewer((void *const)_context, loader, platform, uberArchivePath);
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, _viewer);
|
||||||
|
#else
|
||||||
|
auto viewer = (FilamentViewer *)create_filament_viewer(context, loader, platform, uberArchivePath);
|
||||||
|
_viewer = reinterpret_cast<TViewer*>(viewer);
|
||||||
|
callback(_viewer);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroyViewer(FilamentViewer *viewer)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
|
{
|
||||||
|
_render = false;
|
||||||
|
_viewer = nullptr;
|
||||||
|
destroy_filament_viewer(reinterpret_cast<TViewer*>(viewer)); });
|
||||||
|
auto fut = add_task(lambda);
|
||||||
|
fut.wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doRender()
|
||||||
|
{
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
if (emscripten_is_webgl_context_lost(_context) == EM_TRUE)
|
||||||
|
{
|
||||||
|
Log("Context lost");
|
||||||
|
auto sleepFor = std::chrono::seconds(1);
|
||||||
|
std::this_thread::sleep_for(sleepFor);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
auto rendered = render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||||
|
if (_renderCallback)
|
||||||
|
{
|
||||||
|
_renderCallback(_renderCallbackOwner);
|
||||||
|
}
|
||||||
|
return rendered;
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
// emscripten_webgl_commit_frame();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
_frameIntervalInMicroseconds = static_cast<int>(1000.0f * frameIntervalInMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Rt>
|
||||||
|
auto add_task(std::packaged_task<Rt()> &pt) -> std::future<Rt>
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_mutex);
|
||||||
|
auto ret = pt.get_future();
|
||||||
|
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
|
||||||
|
std::move(pt))]
|
||||||
|
{ (*pt)(); });
|
||||||
|
_cv.notify_one();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _stop = false;
|
||||||
|
bool _render = false;
|
||||||
|
int _frameIntervalInMicroseconds = 1000000 / 60;
|
||||||
|
std::mutex _mutex;
|
||||||
|
std::condition_variable _cv;
|
||||||
|
void (*_renderCallback)(void *const) = nullptr;
|
||||||
|
void *_renderCallbackOwner = nullptr;
|
||||||
|
std::deque<std::function<void()>> _tasks;
|
||||||
|
TViewer *_viewer = nullptr;
|
||||||
|
std::chrono::high_resolution_clock::time_point _lastFrameTime;
|
||||||
|
int _frameCount = 0;
|
||||||
|
float _accumulatedTime = 0.0f;
|
||||||
|
float _fps = 0.0f;
|
||||||
|
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
pthread_t t;
|
||||||
|
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
|
||||||
|
#else
|
||||||
|
std::thread *t = nullptr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
static RenderLoop *_rl;
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_render_thread(
|
||||||
|
void *const context, void *const platform, const char *uberArchivePath,
|
||||||
|
const void *const loader,
|
||||||
|
void (*renderCallback)(void *const renderCallbackOwner),
|
||||||
|
void *const renderCallbackOwner,
|
||||||
|
void (*callback)(TViewer *))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (!_rl)
|
||||||
|
{
|
||||||
|
_rl = new RenderLoop();
|
||||||
|
}
|
||||||
|
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapper *const)loader,
|
||||||
|
renderCallback, renderCallbackOwner, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
_rl->destroyViewer((FilamentViewer *)viewer);
|
||||||
|
delete _rl;
|
||||||
|
_rl = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(TViewer *viewer,
|
||||||
|
void *const surface,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
void (*onComplete)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]() mutable
|
||||||
|
{
|
||||||
|
create_swap_chain(viewer, surface, width, height);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||||
|
#else
|
||||||
|
onComplete();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(TViewer *viewer, void (*onComplete)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]() mutable
|
||||||
|
{
|
||||||
|
destroy_swap_chain(viewer);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||||
|
#else
|
||||||
|
onComplete();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(TViewer *viewer,
|
||||||
|
intptr_t nativeTextureId,
|
||||||
|
uint32_t width,
|
||||||
|
uint32_t height,
|
||||||
|
void (*onComplete)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
|
{
|
||||||
|
create_render_target(viewer, nativeTextureId, width, height);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||||
|
#else
|
||||||
|
onComplete();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
if (!_rl)
|
||||||
|
{
|
||||||
|
Log("No render loop!"); // PANIC?
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rl->requestFrame();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void
|
||||||
|
set_frame_interval_render_thread(TViewer *viewer, float frameIntervalInMilliseconds)
|
||||||
|
{
|
||||||
|
_rl->setFrameIntervalInMilliseconds(frameIntervalInMilliseconds);
|
||||||
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
|
{ ((FilamentViewer *)viewer)->setFrameInterval(frameIntervalInMilliseconds); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void render_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
|
{ _rl->doRender(); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void capture_render_thread(TViewer *viewer, uint8_t *pixelBuffer, void (*onComplete)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]() mutable
|
||||||
|
{ capture(viewer, pixelBuffer, onComplete); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void
|
||||||
|
set_background_color_render_thread(TViewer *viewer, const float r, const float g,
|
||||||
|
const float b, const float a)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]() mutable
|
||||||
|
{ set_background_color(viewer, r, g, b, a); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(void *const sceneManager,
|
||||||
|
const char *path,
|
||||||
|
const char *relativeResourcePath,
|
||||||
|
bool keepData,
|
||||||
|
void (*callback)(EntityId))
|
||||||
|
{
|
||||||
|
std::packaged_task<EntityId()> lambda([=]() mutable
|
||||||
|
{
|
||||||
|
auto entity = load_gltf(sceneManager, path, relativeResourcePath, keepData);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({
|
||||||
|
moduleArg.dartFilamentResolveCallback($0, $1);
|
||||||
|
}, callback, entity);
|
||||||
|
#else
|
||||||
|
callback(entity);
|
||||||
|
#endif
|
||||||
|
return entity; });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(void *const sceneManager,
|
||||||
|
const char *path,
|
||||||
|
int numInstances,
|
||||||
|
bool keepData,
|
||||||
|
void (*callback)(EntityId))
|
||||||
|
{
|
||||||
|
std::packaged_task<EntityId()> lambda(
|
||||||
|
[=]() mutable
|
||||||
|
{
|
||||||
|
auto entity = load_glb(sceneManager, path, numInstances, keepData);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, entity);
|
||||||
|
#else
|
||||||
|
callback(entity);
|
||||||
|
#endif
|
||||||
|
return entity;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(void *const sceneManager,
|
||||||
|
const uint8_t *const data,
|
||||||
|
size_t length,
|
||||||
|
int numInstances,
|
||||||
|
bool keepData,
|
||||||
|
int priority,
|
||||||
|
int layer,
|
||||||
|
void (*callback)(EntityId))
|
||||||
|
{
|
||||||
|
std::packaged_task<EntityId()> lambda(
|
||||||
|
[=]() mutable
|
||||||
|
{
|
||||||
|
auto entity = load_glb_from_buffer(sceneManager, data, length, keepData, priority, layer);
|
||||||
|
callback(entity);
|
||||||
|
return entity;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ clear_background_image(viewer); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer,
|
||||||
|
const char *path,
|
||||||
|
bool fillHeight, void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
set_background_image(viewer, path, fillHeight);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||||
|
#else
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer,
|
||||||
|
float x, float y,
|
||||||
|
bool clamp)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{ set_background_image_position(viewer, x, y, clamp); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(TViewer *viewer,
|
||||||
|
int toneMapping)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{ set_tone_mapping(viewer, toneMapping); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(TViewer *viewer, float strength)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ set_bloom(viewer, strength); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer,
|
||||||
|
const char *skyboxPath,
|
||||||
|
void (*onComplete)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{
|
||||||
|
load_skybox(viewer, skyboxPath);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||||
|
#else
|
||||||
|
onComplete();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void load_ibl_render_thread(TViewer *viewer, const char *iblPath,
|
||||||
|
float intensity)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{ load_ibl(viewer, iblPath, intensity); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ remove_skybox(viewer); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_ibl_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ remove_ibl(viewer); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_light_render_thread(
|
||||||
|
TViewer *viewer,
|
||||||
|
uint8_t type,
|
||||||
|
float colour,
|
||||||
|
float intensity,
|
||||||
|
float posX,
|
||||||
|
float posY,
|
||||||
|
float posZ,
|
||||||
|
float dirX,
|
||||||
|
float dirY,
|
||||||
|
float dirZ,
|
||||||
|
float falloffRadius,
|
||||||
|
float spotLightConeInner,
|
||||||
|
float spotLightConeOuter,
|
||||||
|
float sunAngularRadius,
|
||||||
|
float sunHaloSize,
|
||||||
|
float sunHaloFallof,
|
||||||
|
bool shadows,
|
||||||
|
void (*callback)(EntityId))
|
||||||
|
{
|
||||||
|
std::packaged_task<EntityId()> lambda([=]
|
||||||
|
{
|
||||||
|
auto entity = add_light(
|
||||||
|
viewer,
|
||||||
|
type,
|
||||||
|
colour,
|
||||||
|
intensity,
|
||||||
|
posX,
|
||||||
|
posY,
|
||||||
|
posZ,
|
||||||
|
dirX,
|
||||||
|
dirY,
|
||||||
|
dirZ,
|
||||||
|
falloffRadius,
|
||||||
|
spotLightConeInner,
|
||||||
|
spotLightConeOuter,
|
||||||
|
sunAngularRadius,
|
||||||
|
sunHaloSize,
|
||||||
|
sunHaloFallof,
|
||||||
|
shadows);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({
|
||||||
|
moduleArg.dartFilamentResolveCallback($0, $1);
|
||||||
|
}, callback, entity);
|
||||||
|
#else
|
||||||
|
callback(entity);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return entity; });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_light_render_thread(TViewer *viewer,
|
||||||
|
EntityId entityId)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ remove_light(viewer, entityId); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void clear_lights_render_thread(TViewer *viewer)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ clear_lights(viewer); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer,
|
||||||
|
EntityId asset, void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{
|
||||||
|
remove_entity(viewer, asset);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||||
|
#else
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{
|
||||||
|
clear_entities(viewer);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||||
|
#else
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(TViewer *viewer, EntityId asset,
|
||||||
|
const char *nodeName, void (*callback)(bool))
|
||||||
|
{
|
||||||
|
std::packaged_task<bool()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto success = set_camera(viewer, asset, nodeName);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, success);
|
||||||
|
#else
|
||||||
|
callback(success);
|
||||||
|
#endif
|
||||||
|
return success;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void
|
||||||
|
get_morph_target_name_render_thread(void *sceneManager, EntityId assetEntity,
|
||||||
|
EntityId childEntity, char *const outPtr, int index, void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{
|
||||||
|
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||||
|
#else
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void
|
||||||
|
get_morph_target_name_count_render_thread(void *sceneManager, EntityId assetEntity,
|
||||||
|
EntityId childEntity, void (*callback)(int))
|
||||||
|
{
|
||||||
|
std::packaged_task<int()> lambda([=]
|
||||||
|
{
|
||||||
|
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({
|
||||||
|
moduleArg.dartFilamentResolveCallback($0,$1);
|
||||||
|
}, callback, count);
|
||||||
|
#else
|
||||||
|
callback(count);
|
||||||
|
#endif
|
||||||
|
return count; });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(void *const sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
int animationIndex,
|
||||||
|
int animationFrame)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda([=]
|
||||||
|
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(void *const sceneManager,
|
||||||
|
EntityId asset, int index)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{ stop_animation(sceneManager, asset, index); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(void *const sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
void (*callback)(int))
|
||||||
|
{
|
||||||
|
std::packaged_task<int()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto count = get_animation_count(sceneManager, asset);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, count);
|
||||||
|
#else
|
||||||
|
callback(count);
|
||||||
|
#endif
|
||||||
|
return count;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(void *const sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
char *const outPtr,
|
||||||
|
int index,
|
||||||
|
void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
get_animation_name(sceneManager, asset, outPtr, index);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||||
|
#else
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer,
|
||||||
|
bool enabled)
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{ set_post_processing(viewer, enabled); });
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void
|
||||||
|
get_name_for_entity_render_thread(void *const sceneManager, const EntityId entityId, void (*callback)(const char *))
|
||||||
|
{
|
||||||
|
std::packaged_task<const char *()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto name = get_name_for_entity(sceneManager, entityId);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, name);
|
||||||
|
#else
|
||||||
|
callback(name);
|
||||||
|
#endif
|
||||||
|
return name;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_morph_target_weights_render_thread(void *const sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
const float *const morphData,
|
||||||
|
int numWeights,
|
||||||
|
void (*callback)(bool))
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, result);
|
||||||
|
#else
|
||||||
|
callback(result);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
|
||||||
|
void *sceneManager,
|
||||||
|
EntityId asset,
|
||||||
|
int skinIndex,
|
||||||
|
int boneIndex,
|
||||||
|
const float *const transform,
|
||||||
|
void (*callback)(bool))
|
||||||
|
{
|
||||||
|
std::packaged_task<bool()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, success);
|
||||||
|
#else
|
||||||
|
callback(success);
|
||||||
|
#endif
|
||||||
|
return success;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(void *sceneManager,
|
||||||
|
EntityId entity, void (*callback)(bool))
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto success = update_bone_matrices(sceneManager, entity);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback, success);
|
||||||
|
#else
|
||||||
|
callback(success);
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(void *const sceneManager, EntityId entityId, void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
reset_to_rest_pose(sceneManager, entityId);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||||
|
#else
|
||||||
|
callback();
|
||||||
|
#endif
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
|
||||||
|
void *const sceneManager,
|
||||||
|
float *vertices,
|
||||||
|
int numVertices,
|
||||||
|
float *normals,
|
||||||
|
int numNormals,
|
||||||
|
float *uvs,
|
||||||
|
int numUvs,
|
||||||
|
uint16_t *indices,
|
||||||
|
int numIndices,
|
||||||
|
int primitiveType,
|
||||||
|
TMaterialInstance *materialInstance,
|
||||||
|
bool keepData,
|
||||||
|
void (*callback)(EntityId))
|
||||||
|
{
|
||||||
|
std::packaged_task<EntityId()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
auto entity = create_geometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstance, keepData);
|
||||||
|
#ifdef __EMSCRIPTEN__
|
||||||
|
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, entity);
|
||||||
|
#else
|
||||||
|
callback(entity);
|
||||||
|
#endif
|
||||||
|
return entity;
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
|
||||||
|
{
|
||||||
|
std::packaged_task<void()> lambda(
|
||||||
|
[=]
|
||||||
|
{
|
||||||
|
unproject_texture(viewer, entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
auto fut = _rl->add_task(lambda);
|
||||||
|
}
|
||||||
|
}
|
||||||
211
thermion_dart/native/src/UnprojectTexture.cpp
Normal file
211
thermion_dart/native/src/UnprojectTexture.cpp
Normal file
@@ -0,0 +1,211 @@
|
|||||||
|
#include <filament/Engine.h>
|
||||||
|
#include <filament/Camera.h>
|
||||||
|
#include <filament/Texture.h>
|
||||||
|
#include <filament/VertexBuffer.h>
|
||||||
|
#include <filament/IndexBuffer.h>
|
||||||
|
#include <filament/RenderableManager.h>
|
||||||
|
#include <filament/TransformManager.h>
|
||||||
|
#include <math/mat4.h>
|
||||||
|
#include <math/vec2.h>
|
||||||
|
#include <math/vec3.h>
|
||||||
|
#include <math/vec4.h>
|
||||||
|
#include <utils/EntityManager.h>
|
||||||
|
#include <backend/PixelBufferDescriptor.h>
|
||||||
|
#include "Log.hpp"
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "CustomGeometry.hpp"
|
||||||
|
#include "UnprojectTexture.hpp"
|
||||||
|
|
||||||
|
namespace thermion_filament
|
||||||
|
{
|
||||||
|
|
||||||
|
bool UnprojectTexture::isInsideTriangle(const math::float2 &p, const math::float2 &a, const math::float2 &b, const math::float2 &c)
|
||||||
|
{
|
||||||
|
float d1 = (p.x - b.x) * (a.y - b.y) - (a.x - b.x) * (p.y - b.y);
|
||||||
|
float d2 = (p.x - c.x) * (b.y - c.y) - (b.x - c.x) * (p.y - c.y);
|
||||||
|
float d3 = (p.x - a.x) * (c.y - a.y) - (c.x - a.x) * (p.y - a.y);
|
||||||
|
return (d1 >= 0 && d2 >= 0 && d3 >= 0) || (d1 <= 0 && d2 <= 0 && d3 <= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
math::float3 UnprojectTexture::barycentric(const math::float2 &p, const math::float2 &a, const math::float2 &b, const math::float2 &c)
|
||||||
|
{
|
||||||
|
math::float2 v0 = b - a;
|
||||||
|
math::float2 v1 = c - a;
|
||||||
|
math::float2 v2 = p - a;
|
||||||
|
|
||||||
|
float d00 = dot(v0, v0);
|
||||||
|
float d01 = dot(v0, v1);
|
||||||
|
float d11 = dot(v1, v1);
|
||||||
|
float d20 = dot(v2, v0);
|
||||||
|
float d21 = dot(v2, v1);
|
||||||
|
|
||||||
|
float denom = d00 * d11 - d01 * d01;
|
||||||
|
|
||||||
|
float v = (d11 * d20 - d01 * d21) / denom;
|
||||||
|
float w = (d00 * d21 - d01 * d20) / denom;
|
||||||
|
float u = 1.0f - v - w;
|
||||||
|
|
||||||
|
return math::float3(u, v, w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnprojectTexture::unproject(utils::Entity entity, const uint8_t *inputTexture, uint8_t *outputTexture,
|
||||||
|
uint32_t inputWidth, uint32_t inputHeight,
|
||||||
|
uint32_t outputWidth, uint32_t outputHeight)
|
||||||
|
{
|
||||||
|
|
||||||
|
auto &rm = _engine->getRenderableManager();
|
||||||
|
|
||||||
|
auto &tm = _engine->getTransformManager();
|
||||||
|
|
||||||
|
math::mat4 invViewProj = Camera::inverseProjection(_camera.getProjectionMatrix()) * _camera.getModelMatrix();
|
||||||
|
|
||||||
|
auto ti = tm.getInstance(entity);
|
||||||
|
math::mat4f worldTransform = tm.getWorldTransform(ti);
|
||||||
|
auto inverseWorldTransform = inverse(worldTransform);
|
||||||
|
|
||||||
|
const float *vertices = _geometry->vertices;
|
||||||
|
const float *uvs = _geometry->uvs;
|
||||||
|
const uint16_t *indices = _geometry->indices;
|
||||||
|
uint32_t numIndices = _geometry->numIndices;
|
||||||
|
|
||||||
|
// Create a depth buffer
|
||||||
|
std::vector<float> depthBuffer(inputWidth * inputHeight, std::numeric_limits<float>::infinity());
|
||||||
|
|
||||||
|
// Create a buffer to store the triangle index for each pixel
|
||||||
|
std::vector<int> triangleIndexBuffer(inputWidth * inputHeight, -1);
|
||||||
|
|
||||||
|
auto max = 0.0f;
|
||||||
|
auto min = 99.0f;
|
||||||
|
|
||||||
|
// Depth pre-pass
|
||||||
|
for (size_t i = 0; i < numIndices; i += 3)
|
||||||
|
{
|
||||||
|
math::float3 v0(vertices[indices[i] * 3], vertices[indices[i] * 3 + 1], vertices[indices[i] * 3 + 2]);
|
||||||
|
math::float3 v1(vertices[indices[i + 1] * 3], vertices[indices[i + 1] * 3 + 1], vertices[indices[i + 1] * 3 + 2]);
|
||||||
|
math::float3 v2(vertices[indices[i + 2] * 3], vertices[indices[i + 2] * 3 + 1], vertices[indices[i + 2] * 3 + 2]);
|
||||||
|
|
||||||
|
math::float2 uv0(uvs[(indices[i] * 2)], uvs[(indices[i] * 2) + 1]);
|
||||||
|
math::float2 uv1(uvs[(indices[i + 1] * 2)], uvs[(indices[i + 1] * 2) + 1]);
|
||||||
|
math::float2 uv2(uvs[(indices[i + 2] * 2)], uvs[(indices[i + 2] * 2) + 1]);
|
||||||
|
|
||||||
|
// Transform vertices to world space
|
||||||
|
v0 = (worldTransform * math::float4(v0, 1.0f)).xyz;
|
||||||
|
v1 = (worldTransform * math::float4(v1, 1.0f)).xyz;
|
||||||
|
v2 = (worldTransform * math::float4(v2, 1.0f)).xyz;
|
||||||
|
|
||||||
|
// Project vertices to screen space
|
||||||
|
math::float4 clipPos0 = _camera.getProjectionMatrix() * _camera.getViewMatrix() * math::float4(v0, 1.0f);
|
||||||
|
math::float4 clipPos1 = _camera.getProjectionMatrix() * _camera.getViewMatrix() * math::float4(v1, 1.0f);
|
||||||
|
math::float4 clipPos2 = _camera.getProjectionMatrix() * _camera.getViewMatrix() * math::float4(v2, 1.0f);
|
||||||
|
|
||||||
|
math::float3 ndcPos0 = clipPos0.xyz / clipPos0.w;
|
||||||
|
math::float3 ndcPos1 = clipPos1.xyz / clipPos1.w;
|
||||||
|
math::float3 ndcPos2 = clipPos2.xyz / clipPos2.w;
|
||||||
|
|
||||||
|
// Convert NDC to screen coordinates
|
||||||
|
math::float2 screenPos0((ndcPos0.x * 0.5f + 0.5f) * inputWidth, (1.0f - (ndcPos0.y * 0.5f + 0.5f)) * inputHeight);
|
||||||
|
math::float2 screenPos1((ndcPos1.x * 0.5f + 0.5f) * inputWidth, (1.0f - (ndcPos1.y * 0.5f + 0.5f)) * inputHeight);
|
||||||
|
math::float2 screenPos2((ndcPos2.x * 0.5f + 0.5f) * inputWidth, (1.0f - (ndcPos2.y * 0.5f + 0.5f)) * inputHeight);
|
||||||
|
|
||||||
|
// Compute bounding box of the triangle
|
||||||
|
int minX = std::max(0, static_cast<int>(std::min({screenPos0.x, screenPos1.x, screenPos2.x})));
|
||||||
|
int maxX = std::min(static_cast<int>(inputWidth) - 1, static_cast<int>(std::max({screenPos0.x, screenPos1.x, screenPos2.x})));
|
||||||
|
int minY = std::max(0, static_cast<int>(std::min({screenPos0.y, screenPos1.y, screenPos2.y})));
|
||||||
|
int maxY = std::min(static_cast<int>(inputHeight) - 1, static_cast<int>(std::max({screenPos0.y, screenPos1.y, screenPos2.y})));
|
||||||
|
|
||||||
|
// Iterate over the bounding box
|
||||||
|
for (int y = minY; y <= maxY; ++y)
|
||||||
|
{
|
||||||
|
for (int x = minX; x <= maxX; ++x)
|
||||||
|
{
|
||||||
|
math::float2 pixelPos(x + 0.5f, y + 0.5f);
|
||||||
|
|
||||||
|
if (isInsideTriangle(pixelPos, screenPos0, screenPos1, screenPos2))
|
||||||
|
{
|
||||||
|
math::float3 bary = barycentric(pixelPos, screenPos0, screenPos1, screenPos2);
|
||||||
|
|
||||||
|
// Interpolate depth
|
||||||
|
float depth = bary.x * ndcPos0.z + bary.y * ndcPos1.z + bary.z * ndcPos2.z;
|
||||||
|
|
||||||
|
// Depth test
|
||||||
|
if (depth < depthBuffer[y * inputWidth + x])
|
||||||
|
{
|
||||||
|
|
||||||
|
if (depth > max)
|
||||||
|
{
|
||||||
|
max = depth;
|
||||||
|
}
|
||||||
|
if (depth < min)
|
||||||
|
{
|
||||||
|
min = depth;
|
||||||
|
}
|
||||||
|
depthBuffer[y * inputWidth + x] = depth;
|
||||||
|
triangleIndexBuffer[y * inputWidth + x] = i / 3; // Store triangle index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < outputHeight; ++y)
|
||||||
|
{
|
||||||
|
for (uint32_t x = 0; x < outputWidth; ++x)
|
||||||
|
{
|
||||||
|
|
||||||
|
math::float2 uv(static_cast<float>(x) / outputWidth, static_cast<float>(y) / outputHeight);
|
||||||
|
|
||||||
|
// Use the UV coordinates to get the corresponding 3D position on the renderable
|
||||||
|
math::float3 objectPos;
|
||||||
|
math::float2 interpolatedUV;
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
// Iterate over triangles to find which one contains this UV coordinate
|
||||||
|
for (size_t i = 0; i < numIndices; i += 3)
|
||||||
|
{
|
||||||
|
math::float2 uv0 = *(math::float2 *)&uvs[indices[i] * 2];
|
||||||
|
math::float2 uv1 = *(math::float2 *)&uvs[indices[i + 1] * 2];
|
||||||
|
math::float2 uv2 = *(math::float2 *)&uvs[indices[i + 2] * 2];
|
||||||
|
|
||||||
|
if (isInsideTriangle(uv, uv0, uv1, uv2))
|
||||||
|
{
|
||||||
|
// Compute barycentric coordinates in UV space
|
||||||
|
math::float3 bary = barycentric(uv, uv0, uv1, uv2);
|
||||||
|
|
||||||
|
// Interpolate 3D position
|
||||||
|
math::float3 v0(vertices[indices[i] * 3], vertices[indices[i] * 3 + 1], vertices[indices[i] * 3 + 2]);
|
||||||
|
math::float3 v1(vertices[indices[i + 1] * 3], vertices[indices[i + 1] * 3 + 1], vertices[indices[i + 1] * 3 + 2]);
|
||||||
|
math::float3 v2(vertices[indices[i + 2] * 3], vertices[indices[i + 2] * 3 + 1], vertices[indices[i + 2] * 3 + 2]);
|
||||||
|
|
||||||
|
objectPos = v0 * bary.x + v1 * bary.y + v2 * bary.z;
|
||||||
|
interpolatedUV = uv;
|
||||||
|
|
||||||
|
// Find the screen coordinates on the input texture
|
||||||
|
math::float3 worldPos = (worldTransform * math::float4(objectPos, 1.0f)).xyz;
|
||||||
|
// Project the world position to screen space
|
||||||
|
math::float4 clipPos = _camera.getProjectionMatrix() * _camera.getViewMatrix() * math::float4(worldPos, 1.0f);
|
||||||
|
math::float3 ndcPos = clipPos.xyz / clipPos.w;
|
||||||
|
// Convert NDC to screen coordinates
|
||||||
|
uint32_t screenX = (ndcPos.x * 0.5f + 0.5f) * inputWidth;
|
||||||
|
uint32_t screenY = (1.0f - (ndcPos.y * 0.5f + 0.5f)) * inputHeight;
|
||||||
|
|
||||||
|
if (triangleIndexBuffer[(screenY * inputWidth) + screenX] == i / 3)
|
||||||
|
{
|
||||||
|
if (screenX >= 0 && screenX < inputWidth && screenY >= 0 && screenY < inputHeight)
|
||||||
|
{
|
||||||
|
int inputIndex = (screenY * inputWidth + screenX) * 4;
|
||||||
|
int outputIndex = (y * outputWidth + x) * 4;
|
||||||
|
std::copy_n(&inputTexture[inputIndex], 4, &outputTexture[outputIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace thermion_filament
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ endif(NOT CMAKE_BUILD_TYPE)
|
|||||||
set(MODULE_NAME "thermion_dart")
|
set(MODULE_NAME "thermion_dart")
|
||||||
|
|
||||||
set(EMCC_CFLAGS --bind)
|
set(EMCC_CFLAGS --bind)
|
||||||
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sALLOW_TABLE_GROWTH=1)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sALLOW_TABLE_GROWTH=1)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sALLOW_MEMORY_GROWTH=1)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sALLOW_MEMORY_GROWTH=1)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORT_NAME=${MODULE_NAME})
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORT_NAME=${MODULE_NAME})
|
||||||
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORT_ALL=1)
|
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORT_ALL=1)
|
||||||
@@ -19,7 +19,7 @@ set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORT_NAME=${MODULE_NAME})
|
|||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sINITIAL_MEMORY=512mb)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sINITIAL_MEMORY=512mb)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sMODULARIZE)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sMODULARIZE)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sERROR_ON_UNDEFINED_SYMBOLS=0 )
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sERROR_ON_UNDEFINED_SYMBOLS=0 )
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORTED_RUNTIME_METHODS=wasmExports,wasmTable,addFunction,ccall,cwrap,allocate,intArrayFromString,intArrayToString,getValue,setValue,UTF8ToString,stringToUTF8,writeArrayToMemory)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORTED_RUNTIME_METHODS=wasmExports,wasmTable,addFunction,removeFunction,ccall,cwrap,allocate,intArrayFromString,intArrayToString,getValue,setValue,UTF8ToString,stringToUTF8,writeArrayToMemory)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORTED_FUNCTIONS=_malloc,stackAlloc,_free)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sEXPORTED_FUNCTIONS=_malloc,stackAlloc,_free)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sFULL_ES3)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sFULL_ES3)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sASSERTIONS)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sASSERTIONS)
|
||||||
@@ -27,7 +27,7 @@ set(EMCC_CFLAGS ${EMCC_CFLAGS} -sASSERTIONS)
|
|||||||
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sALLOW_BLOCKING_ON_MAIN_THREAD=0)
|
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sALLOW_BLOCKING_ON_MAIN_THREAD=0)
|
||||||
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sOFFSCREEN_FRAMEBUFFER=1)
|
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sOFFSCREEN_FRAMEBUFFER=1)
|
||||||
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sOFFSCREENCANVAS_SUPPORT=1)
|
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sOFFSCREENCANVAS_SUPPORT=1)
|
||||||
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sNO_DISABLE_EXCEPTION_CATCHING)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sNO_DISABLE_EXCEPTION_CATCHING)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sASYNCIFY=1)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sASYNCIFY=1)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sMIN_WEBGL_VERSION=2)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sMIN_WEBGL_VERSION=2)
|
||||||
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sMAX_WEBGL_VERSION=2)
|
set(EMCC_CFLAGS ${EMCC_CFLAGS} -sMAX_WEBGL_VERSION=2)
|
||||||
@@ -55,6 +55,8 @@ add_executable(${MODULE_NAME}
|
|||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/FilamentViewer.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/Gizmo.cpp"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/GridOverlay.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/StreamBufferAdapter.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/StreamBufferAdapter.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/TimeIt.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/TimeIt.cpp"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/camutils/Manipulator.cpp"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../src/camutils/Manipulator.cpp"
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
name: thermion_dart
|
name: thermion_dart
|
||||||
description: 3D rendering toolkit for Dart.
|
description: 3D rendering toolkit for Dart.
|
||||||
version: 0.1.3
|
version: 0.2.0-dev.1.0
|
||||||
homepage: https://thermion.dev
|
homepage: https://thermion.dev
|
||||||
repository: https://github.com/nmfisher/thermion
|
repository: https://github.com/nmfisher/thermion
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.0 <4.0.0"
|
sdk: ">=3.5.0 <4.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
vector_math: ^2.1.2
|
vector_math: ^2.1.2
|
||||||
@@ -14,9 +14,12 @@ dependencies:
|
|||||||
animation_tools_dart: ^0.0.4
|
animation_tools_dart: ^0.0.4
|
||||||
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: ^1.0.0
|
||||||
logging: ^1.2.0
|
logging: ^1.2.0
|
||||||
|
http: ^1.2.2
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
ffigen: ^12.0.0
|
ffigen: ^12.0.0
|
||||||
test:
|
test:
|
||||||
|
image:
|
||||||
|
path:
|
||||||
BIN
thermion_dart/test/cube.glb
Normal file
BIN
thermion_dart/test/cube.glb
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user