Compare commits

...

53 Commits

Author SHA1 Message Date
Nick Fisher
961b2ae1ee chore(release): publish packages
- thermion_dart@0.3.3
 - thermion_flutter_method_channel@0.3.3
 - thermion_flutter_platform_interface@0.3.3
 - thermion_flutter_web@0.3.3
 - thermion_flutter@0.3.3
2025-07-24 11:40:35 +08:00
Nick Fisher
a7ac118899 chore(release): publish packages
- thermion_dart@0.3.3-pre
 - thermion_flutter@0.3.3-pre
 - thermion_flutter_method_channel@0.3.3-pre
 - thermion_flutter_platform_interface@0.3.3-pre
 - thermion_flutter_web@0.3.3-pre
2025-07-17 12:13:53 +08:00
Nick Fisher
d92ad4ef12 feat: allow passing renderTargetColorTextureFormat via ThermionFlutterOptions 2025-07-17 12:11:20 +08:00
Nick Fisher
437e91e7bd fix: fix Windows build.dart 2025-07-17 10:54:00 +08:00
Nick Fisher
e169bf6c41 nit: reorder build.dart imports 2025-07-16 18:33:47 +08:00
Nick Fisher
23b060c329 nit: change gltf logging from Log to TRACE 2025-07-16 18:33:47 +08:00
Nick Fisher
5fd0a10630 re-enable EMSCRIPTEN_KEEPALIVE qualifiers for headers. These are not needed for Emscripten builds but the same name is used for Windows __declspec(dllimport), so this is still needed on Windows. We should probably rename this to API_EXPORT or something similar 2025-07-16 18:33:47 +08:00
Nick Fisher
ddfb649733 ci: add windows workflow 2025-07-16 18:15:04 +08:00
Nick Fisher
ecffc5b62a use async loading for camera_manipulation sample 2025-07-16 18:08:21 +08:00
Nick Fisher
429b8eb93b doc: improve addToScene/removeFromScene documentation 2025-07-16 13:00:27 +08:00
Nick Fisher
413faec849 fix: add nan/negative checks inside setLensProjection 2025-07-14 11:50:52 +08:00
Nick Fisher
433b6373a9 docs: replace thermion_flutter README with symlink to thermion_dart README 2025-07-14 10:13:58 +08:00
Nick Fisher
ad2c5afb7f docs: update contributor list 2025-07-14 10:13:38 +08:00
Nick Fisher
a561c847a7 (test) don't load dylib on macos in testing 2025-07-09 10:47:22 +08:00
Nick Fisher
ef7ba24ecc don't fade grid axes depending on camera angle 2025-07-09 10:46:37 +08:00
Nick Fisher
ee176d2684 explicitly list packages in melos.yaml 2025-07-09 10:41:53 +08:00
Nick Fisher
fa168df28f chore(release): publish packages
- thermion_dart@0.3.2
 - thermion_flutter@0.3.2
 - thermion_flutter_method_channel@0.3.2
 - thermion_flutter_web@0.3.2
 - thermion_flutter_platform_interface@0.3.2
2025-07-08 11:48:25 +08:00
Nick Fisher
ba3d016c1a fix: add missing destroySwapchain argument for web 2025-07-08 11:47:47 +08:00
Nick Fisher
e04d8e76c2 chore(release): publish packages
- thermion_dart@0.3.1
 - thermion_flutter@0.3.1
 - thermion_flutter_method_channel@0.3.1
 - thermion_flutter_web@0.3.1
 - thermion_flutter_platform_interface@0.3.1
2025-07-08 10:33:06 +08:00
Nick Fisher
353b33b7c3 fix: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets 2025-07-07 17:37:28 +08:00
Nick Fisher
3c1b26af2c reverse orientation of camera volume 'lens' 2025-07-07 17:21:43 +08:00
Nick Fisher
b4ea80a84c don't allow creating instances for GridOverlay asset and only expose a single entity 2025-07-07 17:21:43 +08:00
Nick Fisher
db44bc6f74 formatting 2025-07-07 17:19:47 +08:00
Nick Fisher
c668549fb0 fix: add flush() to skybox/IBL destroy methods to ensure that textre upload callbacks are completed to avoid stalling 2025-07-07 17:19:36 +08:00
Nick Fisher
a66703b61c (flutter) (example) cleanup 2025-07-07 17:19:06 +08:00
Nick Fisher
cb8943ff72 formatting 2025-07-07 17:18:43 +08:00
Nick Fisher
9f59577f90 fix: duplicate setting for _grid 2025-07-07 16:40:15 +08:00
Nick Fisher
b86145d4c6 refactor: remove covariant keyword from createInstance args 2025-07-04 22:37:15 +08:00
Nick Fisher
cb8672f120 docs: remove camera_manipulation document 2025-07-03 17:49:51 +08:00
Nick Fisher
92578426ac docs: update quickstart 2025-07-03 17:17:44 +08:00
Nick Fisher
4a6479c4d8 docs: fix typo in link 2025-07-03 17:13:47 +08:00
Nick Fisher
2244d3fcb6 docs: remove code from thermion_flutter README.md and point to docs/repository example instead 2025-07-03 17:12:45 +08:00
Nick Fisher
003fd59269 (web) add -Wno-invalid-specialization 2025-07-03 16:23:24 +08:00
Nick Fisher
77e6ef7568 (CI) move to macos for web build 2025-07-03 16:15:20 +08:00
Nick Fisher
6f07d406f8 (CI) move compile-web-wasm to own step 2025-07-03 16:05:49 +08:00
Nick Fisher
bf5551e278 update Makefile to download wasm release libs 2025-07-03 15:51:23 +08:00
Nick Fisher
64577af352 (CI): update web build 2025-07-03 15:27:54 +08:00
Nick Fisher
951894be41 update CHANGELOG 2025-07-03 15:25:14 +08:00
Nick Fisher
c64b2b8659 docs: update showcase 2025-07-03 15:10:11 +08:00
Nick Fisher
322e77d2b7 add additional camera geometry object 2025-07-03 15:00:02 +08:00
Nick Fisher
a8a52bb2f4 docs: update quickstart/getting started/viewer docs 2025-07-03 14:32:07 +08:00
Nick Fisher
c7dfd293e2 (web) add cplusplus guards for material header 2025-07-03 14:22:26 +08:00
Nick Fisher
cf2498b45f (docs) update web 2025-07-03 14:22:08 +08:00
Nick Fisher
edb7538c36 (example) update viewer example + docs 2025-07-03 14:22:01 +08:00
Nick Fisher
b023e2fb97 chore(release): publish packages
- thermion_dart@0.3.0
 - thermion_flutter@0.3.0
 - thermion_flutter_method_channel@0.3.0
 - thermion_flutter_web@0.3.0
 - thermion_flutter_platform_interface@0.3.0
2025-07-03 13:33:19 +08:00
Nick Fisher
b51cc4b1d1 (flutter) remove direct local dependency in pubspec.yaml 2025-07-03 13:16:06 +08:00
Nick Fisher
d995ed8843 (flutter) cleanup widgets to satisfy pub.dev analyzer 2025-07-03 13:15:50 +08:00
Nick Fisher
b0d34bf6a8 (flutter) rename setExposure method in camera widget 2025-07-03 13:13:04 +08:00
Nick Fisher
2e28b0379d bump min Dart constraint to satisfy pub.dev 2025-07-03 13:09:36 +08:00
Nick Fisher
c899e30a7b chore(release): publish packages
- thermion_dart@0.3.0
 - thermion_flutter@0.3.0
 - thermion_flutter_method_channel@0.3.0
 - thermion_flutter_web@0.3.0
 - thermion_flutter_platform_interface@0.3.0
2025-07-03 13:04:44 +08:00
Nick Fisher
37f8558794 add stub method for resizeWebCanvas to make pub.dev happy 2025-07-03 13:04:24 +08:00
Nick Fisher
3cfa26d284 (web) add package:logging to pubspec to make pub.dev happy 2025-07-03 13:00:41 +08:00
Nick Fisher
b22a82e181 delete swift bindings from thermion_dart package 2025-07-03 12:59:28 +08:00
61 changed files with 3120 additions and 3305 deletions

View File

@@ -7,6 +7,20 @@ on:
branches: [ "develop" ]
jobs:
compile-web-wasm:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup CMake
uses: jwlawson/actions-setup-cmake@v2
with:
cmake-version: '3.25.0' # or 'latest'
- name: Setup Emscripten
uses: mymindstorm/setup-emsdk@v14
with:
version: 'latest'
- name: Compile web
run: make wasm
dart-tests:
runs-on: ubuntu-22.04
steps:
@@ -58,7 +72,6 @@ jobs:
path: |
${{ github.workspace }}/thermion_dart/.dart_tool/thermion_dart/log/build.log
retention-days: 5
flutter_examples:
name: flutter_examples
runs-on: macos-latest
@@ -104,8 +117,28 @@ jobs:
# D:\a\thermion\thermion\thermion_dart\.dart_tool\thermion_dart\log\build.log
/Users/runner/work/thermion/thermion/thermion_dart/.dart_tool/thermion_dart/log/build.log
retention-days: 5
flutter_examples_windows:
name: flutter_examples_windows
runs-on: windows-latest
defaults:
run:
working-directory: examples/flutter
steps:
- uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: master
- run: cd quickstart && flutter pub get && flutter build windows
- run: cd picking && flutter pub get && flutter build windows
- name: Upload logs
if: failure() || steps.build.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: build-logs
path: |
D:\a\thermion\thermion\thermion_dart\.dart_tool\thermion_dart\log\build.log
retention-days: 5
# thermion_dart:
# name: thermion_dart
# runs-on: macos-latest

View File

@@ -3,7 +3,7 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## 2025-07-03
## 2025-07-24
### Changes
@@ -11,95 +11,184 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
Packages with breaking changes:
- [`thermion_dart` - `v0.3.0`](#thermion_dart---v030)
- [`thermion_flutter` - `v0.3.0`](#thermion_flutter---v030)
- [`thermion_flutter_method_channel` - `v0.3.0`](#thermion_flutter_method_channel---v030)
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_flutter_web` - `v0.3.0`](#thermion_flutter_web---v030)
- [`thermion_flutter_platform_interface` - `v0.3.0`](#thermion_flutter_platform_interface---v030)
- [`thermion_dart` - `v0.3.3`](#thermion_dart---v033)
- [`thermion_flutter_method_channel` - `v0.3.3`](#thermion_flutter_method_channel---v033)
- [`thermion_flutter_platform_interface` - `v0.3.3`](#thermion_flutter_platform_interface---v033)
- [`thermion_flutter_web` - `v0.3.3`](#thermion_flutter_web---v033)
- [`thermion_flutter` - `v0.3.3`](#thermion_flutter---v033)
---
#### `thermion_dart` - `v0.3.0`
#### `thermion_dart` - `v0.3.3`
- **REFACTOR**: gizmo/input handler improvements.
- **REFACTOR**: add createGizmoRenderThread.
- **REFACTOR**: Gizmo internals.
- **REFACTOR**: dont require GizmoInputHandler to wrap an existing InputHandler (you can do this by creating your own InputHandler that wraps two children.
- **FIX**: glTF instancing when loaded via buffer.
- **FIX**: don't return entity from SceneManager_addLightRenderThread.
- **FIX**: return light entity from SceneManager.
- **FIX**: store reference to material instances in ThermionViewer so they can be cleaned up on dispose.
- **FIX**: remove MaterialInstance from SceneManager storage when destroyed.
- **FIX**: add destroyCamera to ThermionViewer interface.
- **FIX**: UV calculation for geometry.
- **FIX**: use createGizmoRenderThread.
- **FIX**: remove MaterialInstance from SceneManager storage when destroyed.
- **FIX**: move removeIbl to render thread.
- **FIX**: move material/instance creation to render thread.
- **FIX**: allow destroying instances independently of owner.
- **FIX**: remove MaterialInstance from SceneManager storage when destroyed.
- **FIX**: use render thread methods for grid overlay creation and create ubershader instance.
- **FIX**: only use Windows-style ndkRoot when building on Windows.
- **FIX**: set overlay layer visibility when adding grid.
- **FIX**: only use Windows-style ndkRoot when building on Windows.
- **FIX**: when creating geometry, normals/uvs are set to false by default. remove wirefame camera container (can now be replaced by bounding box methods.
- **FIX**: fix highlights after first.
- **FEAT**: remove bounding box from SceneAsset and create renderable wireframe bounding box in ThermionAsset.
- **FEAT**: add setTransparencyMode to Dart Material class.
- **FEAT**: expose attached entity as Stream on GizmoInputHandler.
- **FEAT**: allow custom material for grid overlay, and material creation from Uint8List.
- **FEAT**: allow setting material instance directly on ThermionAsset.
- **FEAT**: allow passing custom material for grid overlay.
- **FEAT**: allow passing custom material for grid overlay.
- **FEAT**: allow passing custom material for grid overlay.
- **FEAT**: more rotation gizmo improvements.
- **FEAT**: rotation gizmo improvements.
- **FEAT**: add rotation gizmo.
- **FEAT**: add rotation gizmo asset + resource file.
- **FEAT**: add rotation gizmo asset + resource file.
- **FEAT**: use existing material instances when creating an instance of GeometrySceneAsset and no material instance is passed.
- **FEAT**: re-implement grid overlay.
- **FEAT**: add gizmo.glb to assets/resources.
- **FEAT**: add TRACE macro.
- **FEAT**: update Filament to v1.56.4.
- **FEAT**: expose setCastShadows/setReceiveShadows.
- **FEAT**: re-add uvScale, vertexScale to unlit material.
- **FEAT**: re-add uvScale, vertexScale to unlit material.
- **BREAKING** **REFACTOR**: move light methods from FilamentViewer to SceneManager/TLightManager and rename clearLights/clearAssets to destroyLights/destroyAssets.
- **BREAKING** **REFACTOR**: rename removeAsset to destroyAsset.
- **BREAKING** **FIX**: rename removeEntity to removeAsset.
- **BREAKING** **FEAT**: change default near/far to 0.1/100.0.
- **BREAKING** **FEAT**: use raw pointer scale (>1 meaning zoom in, <1 meaning zoom out) rather than binary -1/1 for DelegateInputHandler.
- **BREAKING** **FEAT**: remove Viewer setRenderTarget method (use the View method instead).
- Bump "thermion_dart" to `0.3.3`.
#### `thermion_flutter` - `v0.3.0`
#### `thermion_flutter_method_channel` - `v0.3.3`
- **REFACTOR**: rename ThermionFlutterTexture->PlatformTextureDescriptor.
- **FIX**: rename msPerFrame property.
- **FEAT**: add FocusNode to ThermionListenerWidget.
- **FEAT**: use new createTextureAndBindToView in ThermionTextureWidget.
- **BREAKING** **REFACTOR**: move light methods from FilamentViewer to SceneManager/TLightManager and rename clearLights/clearAssets to destroyLights/destroyAssets.
- **BREAKING** **FEAT**: remove superseded ThermionWindows widget.
- **BREAKING** **FEAT**: rename thermion_flutter_ffi package to thermion_flutter_method_channel.
- Bump "thermion_flutter_method_channel" to `0.3.3`.
#### `thermion_flutter_method_channel` - `v0.3.0`
#### `thermion_flutter_platform_interface` - `v0.3.3`
- **REFACTOR**: rename ThermionFlutterTexture->PlatformTextureDescriptor.
- **BREAKING** **FEAT**: rename thermion_flutter_ffi package to thermion_flutter_method_channel.
- Bump "thermion_flutter_platform_interface" to `0.3.3`.
#### `thermion_flutter_web` - `v0.3.0`
#### `thermion_flutter_web` - `v0.3.3`
- **REFACTOR**: rename ThermionFlutterTexture->PlatformTextureDescriptor.
- Bump "thermion_flutter_web" to `0.3.3`.
#### `thermion_flutter_platform_interface` - `v0.3.0`
#### `thermion_flutter` - `v0.3.3`
- **REFACTOR**: rename ThermionFlutterTexture->PlatformTextureDescriptor.
- **FEAT**: create separate createTexture and createTextureAndBindToView interface methods.
- Bump "thermion_flutter" to `0.3.3`.
## 2025-07-17
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.3.3-pre`](#thermion_dart---v033-pre)
- [`thermion_flutter` - `v0.3.3-pre`](#thermion_flutter---v033-pre)
- [`thermion_flutter_method_channel` - `v0.3.3-pre`](#thermion_flutter_method_channel---v033-pre)
- [`thermion_flutter_platform_interface` - `v0.3.3-pre`](#thermion_flutter_platform_interface---v033-pre)
- [`thermion_flutter_web` - `v0.3.3-pre`](#thermion_flutter_web---v033-pre)
---
#### `thermion_dart` - `v0.3.3-pre`
- **FIX**: fix Windows build.dart.
- **FIX**: add nan/negative checks inside setLensProjection.
#### `thermion_flutter` - `v0.3.3-pre`
- **DOCS**: replace thermion_flutter README with symlink to thermion_dart README.
#### `thermion_flutter_method_channel` - `v0.3.3-pre`
- **FEAT**: allow passing renderTargetColorTextureFormat via ThermionFlutterOptions.
#### `thermion_flutter_platform_interface` - `v0.3.3-pre`
- **FEAT**: allow passing renderTargetColorTextureFormat via ThermionFlutterOptions.
#### `thermion_flutter_web` - `v0.3.3-pre`
- Bump "thermion_flutter_web" to `0.3.3-pre`.
## 2025-07-08
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.3.2`](#thermion_dart---v032)
- [`thermion_flutter` - `v0.3.2`](#thermion_flutter---v032)
- [`thermion_flutter_method_channel` - `v0.3.2`](#thermion_flutter_method_channel---v032)
- [`thermion_flutter_web` - `v0.3.2`](#thermion_flutter_web---v032)
- [`thermion_flutter_platform_interface` - `v0.3.2`](#thermion_flutter_platform_interface---v032)
---
#### `thermion_dart` - `v0.3.2`
- Bump "thermion_dart" to `0.3.2`.
#### `thermion_flutter` - `v0.3.2`
- Bump "thermion_flutter" to `0.3.2`.
#### `thermion_flutter_method_channel` - `v0.3.2`
- Bump "thermion_flutter_method_channel" to `0.3.2`.
#### `thermion_flutter_web` - `v0.3.2`
- **FIX**: add missing destroySwapchain argument for web.
#### `thermion_flutter_platform_interface` - `v0.3.2`
- Bump "thermion_flutter_platform_interface" to `0.3.2`.
## 2025-07-08
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.3.1`](#thermion_dart---v031)
- [`thermion_flutter` - `v0.3.1`](#thermion_flutter---v031)
- [`thermion_flutter_method_channel` - `v0.3.1`](#thermion_flutter_method_channel---v031)
- [`thermion_flutter_web` - `v0.3.1`](#thermion_flutter_web---v031)
- [`thermion_flutter_platform_interface` - `v0.3.1`](#thermion_flutter_platform_interface---v031)
---
#### `thermion_dart` - `v0.3.1`
- **REFACTOR**: remove covariant keyword from createInstance args.
- **FIX**: add flush() to skybox/IBL destroy methods to ensure that textre upload callbacks are completed to avoid stalling.
- **FIX**: duplicate setting for _grid.
#### `thermion_flutter` - `v0.3.1`
- **FIX**: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets.
- **DOCS**: fix typo in link.
- **DOCS**: remove code from thermion_flutter README.md and point to docs/repository example instead.
#### `thermion_flutter_method_channel` - `v0.3.1`
- **FIX**: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets.
#### `thermion_flutter_web` - `v0.3.1`
#### `thermion_flutter_platform_interface` - `v0.3.1`
- **FIX**: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets.
# Change Log
#### v0.3.0
This release involved considerable internal refactoring, allowing us to expose more Filament functionality on the Dart side. Previously, most of this functionality was
rigidly implemented in C++ and didn't allow for end-users to take advantage of Filament directly.
This also means there are a number of breaking changes from `0.2.1`. To summarize:
- `ViewerWidget` has been introduced. This is a Flutter widget for users who only need basic rendering and don't need/want to deal with camera/materials/etc directly.
- Users who want more fine-grained control than a `ViewerWidget` can still work with `ThermionViewer` and `ThermionWidget`.
- The singleton `FilamentApp.instance` exposes methods for working almost directly with the underlying Filament engine (e.g. loading custom materials from `Uint8List`, creating textures, etc).
- New interfaces have been added for `Material`, `MaterialInstance`, `Texture`, `View`, `Scene` and `Camera`.
- `ThermionAsset` replaces `ThermionEntity` as the main interface for scene objects.
- Transforms/material instances should be set directly by `asset.setTransform`, `asset.setMaterialInstanceAt`
- Material properties can be set directly on the `MaterialInstance`, e.g. `materialInstance.setParameterFloat4("baseColorFactor", 1.0, 0.0, 0.0, 1.0);
- Linux binaries have been added to `thermion_dart`. This package can be run on Linux (which we are using for CI and automated testing) but there are not yet any Flutter bindings, so `thermion_flutter` cannot run on Linux yet.
- On Windows, `thermion_flutter` now uses the Vulkan backend. This is still experimental and will have limited supported on older hardware (pre-2018).
- Web support for `thermion_dart` has now reached parity with other platforms, though should still be considered experimental. Some manual steps are required to run in a Flutter app or a Dart web app.
## 2025-01-08
### Changes

View File

@@ -1,8 +1,17 @@
wasm:
cd thermion_dart/native/web &&\
mkdir -p build &&\
cd build &&\
emcmake cmake .. &&\
@if [ ! -f thermion_dart/native/web/lib/release/filament-v1.58.0-web-release.zip ]; then \
echo "Downloading filament-v1.58.0-web-release.zip..."; \
mkdir -p thermion_dart/native/web/lib/release; \
curl -L -o thermion_dart/native/web/lib/release/filament-v1.58.0-web-release.zip \
https://pub-c8b6266320924116aaddce03b5313c0a.r2.dev/filament-v1.58.0-web-release.zip; \
echo "Extracting filament-v1.58.0-web-release.zip..."; \
cd thermion_dart/native/web/lib/release && \
unzip filament-v1.58.0-web-release.zip; \
fi
cd thermion_dart/native/web && \
mkdir -p build && \
cd build && \
emcmake cmake .. && \
emmake make
wasm-clean:
cd thermion_dart/native/web && rm -rf build

View File

@@ -79,4 +79,4 @@ Thank you to the following people:
- @LukasPoque for CI/refactoring work
- @alexmercerind for his work on integrating ANGLE textures on Flutter Windows
- @BrutalCoding for documentation fixes
- @chenriji for testing and bug fixes

View File

@@ -7,6 +7,7 @@
"Getting Started",
[
["Overview", "/"],
["Getting Started", "/getting_started"],
["Quick Start", "/quickstart"],
["Viewer", "/viewer"],
["Camera Manipulation", "/camera_manipulation"]

View File

@@ -1,63 +0,0 @@
## Camera Manipulation (Flutter)
> You can find the entire project below in the [flutter/quickstart](https://github.com/nmfisher/thermion/examples/flutter/camera_manipulation) folder.
A `ThermionListenerWidget` is one option for manipulating the camera with an input device (e.g. mouse or touchscreen gestures).
This will generally wrap a `ThermionWidget`, meaning the entire viewport will act as a receiver for gesture events.
> You can position this independently (for example, stacked vertically beneath the viewport), but this will not translate picking queries correctly.
```
@override
Widget build(BuildContext context) {
return Stack(children: [
if (_thermionViewer != null)
Positioned.fill(
child: ThermionListenerWidget(
inputHandler:
DelegateInputHandler.fixedOrbit(_thermionViewer!)
..setActionForType(InputType.MMB_HOLD_AND_MOVE, InputAction.ROTATE)
..setActionForType(InputType.SCALE1, InputAction.ROTATE)
..setActionForType(InputType.SCALE2, InputAction.ZOOM)
..setActionForType(InputType.SCROLLWHEEL, InputAction.ZOOM),
child: ThermionWidget(
viewer: _thermionViewer!,
))),
]);
```
`ThermionListenerWidget` is a very simple widget; it simply forwards pointer, gesture and keyboard events to the provided [InputHandler], which must decide how to interpret those events.
For example, one [InputHandler] implementation might interpret mouse pointer movement as "rotate the camera", whereas a separate implementation might interpret it as "translate this specific entity".
Thermion provides two default InputHandler implementations for manipulating the camera: [DelegateInputHandler.fixedOrbit] and [DelegateInputHandler.flight].
[DelegateInputHandler.fixedOrbit] will rotate the camera in a fixed orbit around a target point (the origin, by default), and also allow zooming in/out (subject to a minimum distance, which is configurable).
By default, [DelegateInputHandler.fixedOrbit] will:
- rotate the camera when the middle mouse button is held and the pointer is moved (on desktop), and when a single swipe left/right/up/down is detected (on mobile)
- zoom the camera when the scroll wheel is scrolled up/down (on desktop), and when a pinch gesture is detected (on mobile)
You can change the action for a specific input type by calling `setActionForType`; for example, if you wanted to rotate the camera by moving the mouse pointer while holding the left mouse button, you would call:
```
setActionForType(InputType.LMB_HOLD_AND_MOVE, InputAction.ROTATE)
```
See the [InputType] and [InputAction] enums for available input types and actions.
[DelegateInputHandler.flight] will translate keyboard and mouse/touchscreen gestures to free flight camera manipulation.
By default:
- holding the middle mouse button will control the pitch/roll/yaw of the camera
- holding the left mouse button will pan the camera left/right/up/down
- the middle mouse button will zoom/dolly the camera in/out
- the WASD keys will pan the camera left/right/up/down and dolly the camera forward/backward
If these don't exactly fit your use case, you can create your own [InputHandler] implementation. If you think it would be useful to other users, please feel free to submit a PR for your implementation to be included in the base Thermion package.

40
docs/getting_started.mdx Normal file
View File

@@ -0,0 +1,40 @@
## Getting Started
Thermion currently requires the Flutter `master` channel with the `native-assets` experiment enabled.
1. Switch to Flutter master channel, upgrade Flutter, create a new project, then add `thermion_flutter` as a dependency
```bash
$ flutter channel master
$ flutter upgrade
$ flutter config --enable-native-assets
$ cd your_flutter_project
$ flutter pub add thermion_flutter
```
2. If running on iOS or MacOS, change the minimum deployment target to OSX 13
<Accordion title="Click to open iOS/MacOS instructions">
Make sure the `platform` entry refers to `13.0` in your Podfile.
In `macos/Podfile` (for macOS):
```
platform :osx, '13.0'
```
In `ios/Podfile`, (for iOS):
```
platform :ios, '13.0'
```
Then open XCode:
```
open macos/Runner.xcworkspace
```
and change the minimum deployment target to 13.0:
![XCode screenshot](images/macos_min_deployment.png)
</Accordion>

View File

@@ -1,23 +1,20 @@
# ViewerWidget Documentation
# Quick Start
`ViewerWidget` is a simplified wrapper around the Thermion 3D viewer that makes it easy to display 3D models in your Flutter application.
If all you need is a quick and easy route to rendering a single 3D model in your Flutter application, start with `ViewerWidget`.
## Overview
This is a simplified, Flutter-only wrapper around the underlying 3D rendering API with sane defaults for most people.
`ViewerWidget` handles the setup and configuration of a Thermion viewer, including:
`ViewerWidget` handles all the setup and configuration of the underlying Thermion API, including:
- Loading 3D models (glTF assets)
- Configuring skyboxes and image-based lighting
- Setting up camera positions and manipulators
- Managing the rendering lifecycle
## Installation
## Setup
First, make sure you have the Thermion Flutter plugin added to your dependencies:
Follow the steps listed in [Getting Started](./getting_started) to configure your Flutter installation and project.
```yaml
dependencies:
thermion_flutter: ^latest_version
```
If you're running Windows, delete the `examples/flutter/quickstart/assets` symlink and copy the `assets` folder from `examples/assets` to `examples/flutter/quickstart/assets`.
## Basic Usage

View File

@@ -1,18 +1,25 @@
## Showcase
## KTX Viewer
https://ktxviewer.com
A basic HTML + Dart site for viewing KTX textures in browser.
## DartPad Playground
A custom DartPad that lets you experiment with Thermion from your browser (currently, only Chrome is supported).
[![Screenshot of Thermion Dartpad](images/dartpad.thermion.dev_.png)](https://dartpad.thermion.dev)
(Outdated, needs to be upgraded to Thermion `0.3.0`);
## mixreel (Flutter/Web)
Create 3D worlds and translate to AI video.
[![Screenshot of the mixreeel app](images/ixlabs.app_app.png)](https://mixreel.ai)
## Nick Fisher
My personal website, where I create an interactive clone of myself with Avaturn & Cartesia (no Flutter, made with Thermion and the [Jaspr Dart UI framework](https://github.com/schultek/jaspr)).
@@ -21,3 +28,4 @@ My personal website, where I create an interactive clone of myself with Avaturn

View File

@@ -1,43 +1,14 @@
## Quickstart (Flutter)
## ThermionViewer (Flutter)
> You can find the entire project below in the [examples/flutter/quickstart](https://github.com/nmfisher/thermion/tree/master/examples/flutter/quickstart) folder of the repository.
If you just want to display a 3D object in the viewport with some basic camera controls, use the [ViewerWidget described in the Quickstart section](./quickstart).
1. Switch to Flutter master channel, upgrade Flutter, create a new project, then add `thermion_flutter` as a dependency
If you need want more fine-grained control
```bash
$ flutter channel master
$ flutter upgrade
$ flutter config --enable-native-assets
$ flutter create thermion_sample_project && cd thermion_sample_project
$ flutter pub add thermion_flutter
```
> You can find the entire project below in the [examples/flutter/viewer](https://github.com/nmfisher/thermion/tree/master/examples/flutter/viewer) folder of the repository.
2. If running on iOS or MacOS, change the minimum deployment target to OSX 13
<Accordion title="Click to open iOS/MacOS instructions">
Make sure the `platform` entry refers to `13.0` in your Podfile.
In `macos/Podfile` (for macOS):
```
platform :osx, '13.0'
```
In `ios/Podfile`, (for iOS):
```
platform :ios, '13.0'
```
Then open XCode:
```
open macos/Runner.xcworkspace
```
and change the minimum deployment target to 13.0:
![XCode screenshot](images/macos_min_deployment.png)
</Accordion>
2. Add a folder containing your assets (glTF model + skybox ktx) to your `pubspec.yaml` asset list
@@ -53,11 +24,11 @@ flutter
```dart
class _MyAppState extends State<MyApp> {
  late ThermionFlutterPlugin _thermionFlutterPlugin; 
late Future<ThermionViewer> _thermionViewer;
  void initState() {   
_thermionFlutterPlugin = ThermionFlutterPlugin();   
_thermionViewer = _thermionFlutterPlugin.createViewer(); 
ThermionFlutterPlugin.createViewer().then((viewer) {
_thermionViewer = viewer;
});
}
}

View File

@@ -1,26 +1,41 @@
## Web
First, you must manually compile the wasm+javascript module. This requires:
Web support is still experimental and currently requires you to manually compile Thermion to WASM first.
Requirements:
1) GNU Make
2) CMake
3) Emscripten
From the project root directory
```
make wasm
thermion % ls -l
total 272
drwxr-xr-x 4 nickfisher staff 128 Jul 3 14:06 assets
-rw-r--r-- 1 nickfisher staff 84532 Jul 3 14:06 CHANGELOG.md
-rw-r--r-- 1 nickfisher staff 2349 Jul 3 14:06 Dockerfile
drwxr-xr-x 19 nickfisher staff 608 Jul 3 14:06 docs
-rw-r--r-- 1 nickfisher staff 748 Jul 3 14:06 docs.json
drwxr-xr-x 7 nickfisher staff 224 Jan 8 17:01 examples
-rw-r--r-- 1 nickfisher staff 11341 Oct 23 2024 LICENSE
-rw-r--r-- 1 nickfisher staff 2161 Jul 3 14:06 Makefile
drwxr-xr-x@ 13 nickfisher staff 416 Jul 3 14:06 materials
-rw-r--r--@ 1 nickfisher staff 517 Oct 23 2024 melos_thermion_workspace.iml
-rw-r--r-- 1 nickfisher staff 77 Oct 23 2024 melos.yaml
-rw-r--r--@ 1 nickfisher staff 9865 Jul 1 13:03 pubspec.lock
-rw-r--r-- 1 nickfisher staff 97 Jun 12 11:38 pubspec.yaml
-rw-r--r-- 1 nickfisher staff 3355 Jul 3 14:06 README.md
drwxr-xr-x@ 22 nickfisher staff 704 Jul 3 14:06 thermion_dart
drwxr-xr-x 7 nickfisher staff 224 Jul 3 14:06 thermion_flutter
thermion % make wasm
```
### Flutter
Thermion requires Android SDK version 22, so change your `app/android/build.gradle` to match this version or higher
Copy thermion_dart.js and thermion_dart.wasm to the `/web` folder for your target app.
```groovy
defaultConfig {
...
minSdk = 22
...
}
```
```
flutter run -d chrome --web-header Cross-Origin-Embedder-Policy=require-corp --web-header Cross-Origin-Opener-Policy=same-origin

View File

@@ -0,0 +1,103 @@
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:logging/logging.dart';
import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion_flutter.dart';
void main() {
runApp(const MyApp());
Logger.root.onRecord.listen((record) {
print(record);
});
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Thermion Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Thermion Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late DelegateInputHandler _fixedOrbitInputHandler;
late DelegateInputHandler _freeFlightInputHandler;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
_thermionViewer = await ThermionFlutterPlugin.createViewer();
var assetData = await rootBundle.load("assets/cube.glb");
var asset =
await _thermionViewer!.loadGltfFromBuffer(assetData.buffer.asUint8List(assetData.offsetInBytes), keepData: true, loadResourcesAsync: true);
await _thermionViewer!.loadSkybox("assets/default_env_skybox.ktx");
await _thermionViewer!.loadIbl("assets/default_env_ibl.ktx");
await _thermionViewer!.setPostProcessing(true);
await _thermionViewer!.setRendering(true);
_fixedOrbitInputHandler =
DelegateInputHandler.fixedOrbit(_thermionViewer!)
..setActionForType(InputType.MMB_HOLD_AND_MOVE, InputAction.ROTATE)
..setActionForType(InputType.SCALE1, InputAction.ROTATE)
..setActionForType(InputType.SCALE2, InputAction.ZOOM)
..setActionForType(InputType.SCROLLWHEEL, InputAction.ZOOM);
_freeFlightInputHandler =
DelegateInputHandler.flight(_thermionViewer!)
..setActionForType(InputType.MMB_HOLD_AND_MOVE, InputAction.ROTATE)
..setActionForType(InputType.SCALE1, InputAction.ROTATE)
..setActionForType(InputType.SCALE2, InputAction.ZOOM)
..setActionForType(InputType.SCROLLWHEEL, InputAction.ZOOM);
setState(() {});
});
}
ThermionViewer? _thermionViewer;
bool isOrbit = true;
@override
Widget build(BuildContext context) {
return Stack(children: [
if (_thermionViewer != null) ...[
Positioned.fill(
child: ThermionListenerWidget(
inputHandler: isOrbit
? _fixedOrbitInputHandler : _freeFlightInputHandler,
child:ThermionWidget(
viewer: _thermionViewer!,
))),
Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
ElevatedButton(
onPressed: () {
isOrbit = !isOrbit;
setState(() {});
},
child: Text("Switch to ${isOrbit ? "Free Flight" : "Orbit"}"))
],
)
],
]);
}
}

View File

@@ -80,7 +80,7 @@ class _MyHomePageState extends State<MyHomePage> {
await _thermionViewer!.loadSkybox("assets/default_env_skybox.ktx");
await _thermionViewer!.loadIbl("assets/default_env_ibl.ktx");
await _thermionViewer!.setBackgroundColor(0, 0, 1, 1);
// await _thermionViewer!.setBackgroundColor(0, 0, 1, 1);
// The underlying Filament rendering engine exposes a number of
// post-processing options (anti-aliasing, bloom, etc).
@@ -93,13 +93,6 @@ class _MyHomePageState extends State<MyHomePage> {
// false is designed to allow you to pause rendering to conserve battery life
await _thermionViewer!.setRendering(true);
// Timer.periodic(Duration(seconds: 1), (_) async {
// final rnd = Random();
// await camera.setLensProjection();
// await _thermionViewer!.setBackgroundColor(rnd.nextDouble(),rnd.nextDouble(), 0, 1.0);
// });
setState(() {});
}
@@ -120,25 +113,16 @@ class _MyHomePageState extends State<MyHomePage> {
child: ElevatedButton(onPressed: _load, child: const Text("Load")));
}
Widget _renderButton() {
Widget _changeBgColor() {
return Center(
child: ElevatedButton(
onPressed: () async {
// final rnd = Random();
// await FilamentApp.instance!.setClearColor(
// rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble(), 1.0);
// final camera = await _thermionViewer!.getActiveCamera();
// await _thermionViewer!.setRendering(false);
// // await camera.setLensProjection();
// await _thermionViewer!.removeSkybox();
// // await _thermionViewer!.setBackgroundColor(rnd.nextDouble(), 1.0, 0, 1.0);
// await _thermionViewer!.clearBackgroundImage(destroy: true);
// // await _thermionViewer!.setBackgroundImage("/Users/nickfisher/Documents/thermion/thermion_dart/test/assets/cube_texture_512x512.png");
// await FilamentApp.instance!.render();
final rnd = Random();
await _thermionViewer!.removeSkybox();
await _thermionViewer!.setBackgroundColor(
rnd.nextDouble(), rnd.nextDouble(), rnd.nextDouble(), 1.0);
},
child: const Text("Render")));
child: const Text("Change background color")));
}
Widget _unloadButton() {
@@ -153,9 +137,9 @@ class _MyHomePageState extends State<MyHomePage> {
body: Stack(children: [
if (_thermionViewer != null)
Positioned.fill(
child: ThermionWidget(
child: ThermionListenerWidget(inputHandler: DelegateInputHandler.fixedOrbit(_thermionViewer!), child:ThermionWidget(
viewer: _thermionViewer!,
)),
))),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
@@ -165,7 +149,7 @@ class _MyHomePageState extends State<MyHomePage> {
mainAxisAlignment: MainAxisAlignment.end,
children: [
if (_thermionViewer == null) _loadButton(),
if (_thermionViewer != null) _renderButton(),
if (_thermionViewer != null) _changeBgColor(),
if (_thermionViewer != null) _unloadButton(),
])))
]));

View File

@@ -558,7 +558,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;
@@ -641,7 +641,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx;
@@ -691,7 +691,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = 10.14;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = macosx;
SWIFT_COMPILATION_MODE = wholemodule;

View File

@@ -108,10 +108,13 @@ fragment {
1.0
);
color.rgb = (axes.x < 1e-8) ? color.rgb : AXIS_COLOR_X;
color.rgb = (axes.z < 1e-8) ? color.rgb : AXIS_COLOR_Z;
material.baseColor = color * gridAlpha;
if(axes.x > 1e-8) {
material.baseColor = vec4(AXIS_COLOR_X, 1.0);
} else if(axes.z > 1e-8) {
material.baseColor = vec4(AXIS_COLOR_Z, 1.0);
} else {
material.baseColor = color * gridAlpha;
}
}
}

View File

@@ -1,4 +1,8 @@
name: thermion_workspace
packages:
- thermion_dart
- thermion_flutter/**
- thermion_flutter/thermion_flutter_platform_interface
- thermion_flutter/thermion_flutter_method_channel
- thermion_flutter/thermion_flutter_web
- thermion_flutter/thermion_flutter

View File

@@ -1,3 +1,26 @@
## 0.3.3
- Bump "thermion_dart" to `0.3.3`.
## 0.3.3-pre
- **FIX**: fix Windows build.dart.
- **FIX**: add nan/negative checks inside setLensProjection.
## 0.3.2
- Bump "thermion_dart" to `0.3.2`.
## 0.3.1
- **REFACTOR**: remove covariant keyword from createInstance args.
- **FIX**: add flush() to skybox/IBL destroy methods to ensure that textre upload callbacks are completed to avoid stalling.
- **FIX**: duplicate setting for _grid.
## 0.3.0
- n
## 0.3.0
> Note: This release has breaking changes.

View File

@@ -1,10 +1,11 @@
import 'dart:io';
import 'package:archive/archive.dart';
import 'package:code_assets/code_assets.dart';
import 'package:hooks/hooks.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';
import 'package:logging/logging.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';
import 'package:path/path.dart' as path;
void main(List<String> args) async {
@@ -130,7 +131,7 @@ void main(List<String> args) async {
var frameworks = [];
if (platform != "windows") {
if (targetOS != OS.windows) {
flags.addAll(['-std=c++17']);
} else {
defines["WIN32"] = "1";
@@ -193,7 +194,7 @@ void main(List<String> args) async {
name: packageName,
language: Language.cpp,
assetName: 'thermion_dart.dart',
sources: platform == "windows" ? [] : sources,
sources: targetOS == OS.windows ? [] : sources,
includes: platform == "windows"
? []
: ['native/include', 'native/include/filament'],
@@ -219,12 +220,12 @@ void main(List<String> args) async {
"/I${path.join(pkgRootFilePath, "native", "include", "windows", "vulkan")}",
"@${srcs.uri.toFilePath(windows: true)}",
// ...sources,
'/link',
"/LIBPATH:$libDir",
'/DLL',
// '/link',
// "/LIBPATH:$libDir",
// '/DLL',
]
],
dartBuildFiles: ['hook/build.dart'],
libraryDirectories: [libDir],
);
await cbuilder.run(

View File

@@ -221,8 +221,11 @@ extension DartBigIntExtension on int {
}
extension Float32ListExtension on Float32List {
Uint8List asUint8List() {
return this.buffer.asUint8List(this.offsetInBytes);
}
}
}
void resizeWebCanvas(int width, int height) {
throw UnsupportedError("Not supported on non-web platforms");
}

View File

@@ -157,7 +157,6 @@ extension Uint8ListExtension on Uint8List {
extension Float32ListExtension on Float32List {
Pointer<Float32> get address {
final ptr = getPointer<Float32>(this, this.toJS);
final bar =
Float32ArrayWrapper(NativeLibrary.instance.HEAPU8.buffer, ptr, length)
@@ -167,7 +166,8 @@ extension Float32ListExtension on Float32List {
}
Uint8List asUint8List() {
var ptr = Pointer<Uint8>(_NativeLibrary.instance._emscripten_get_byte_offset(this.toJS));
var ptr = Pointer<Uint8>(
_NativeLibrary.instance._emscripten_get_byte_offset(this.toJS));
return ptr.asTypedList(length * 4);
}
}
@@ -468,3 +468,7 @@ void stackRestore(Pointer ptr) =>
void getStackFree() {
print(_NativeLibrary.instance._emscripten_stack_get_free());
}
void resizeWebCanvas(int width, int height) {
Thermion_resizeCanvas(width, height);
}

View File

@@ -132,7 +132,7 @@ class FFIAsset extends ThermionAsset {
///
@override
Future<FFIAsset> createInstance(
{covariant List<MaterialInstance>? materialInstances = null}) async {
{List<MaterialInstance>? materialInstances = null}) async {
if(isInstance) {
return instanceOwner!.createInstance(materialInstances: materialInstances);
}

View File

@@ -5,11 +5,10 @@ import '../../../utils/src/matrix.dart';
class FFICamera extends Camera<Pointer<TCamera>> {
final Pointer<TCamera> camera;
@override
Pointer<TCamera> getNativeHandle() {
return camera;
}
final FFIFilamentApp app;
@@ -92,6 +91,16 @@ class FFICamera extends Camera<Pointer<TCamera>> {
double far = kFar,
double aspect = 1.0,
double focalLength = kFocalLength}) async {
if (near.isNaN ||
far.isNaN ||
aspect.isNaN ||
focalLength.isNaN ||
near.isNegative ||
far.isNegative ||
aspect.isNegative ||
focalLength.isNegative) {
throw FormatException();
}
Camera_setLensProjection(camera, near, far, aspect, focalLength);
}

View File

@@ -12,16 +12,39 @@ class GridOverlay extends FFIAsset {
static Future<GridOverlay> create(
FFIFilamentApp app, Pointer<TAnimationManager> animationManager) async {
if (_overlay == null) {
_gridMaterial ??= FFIMaterial(Material_createGridMaterial(app.engine), app);
_gridMaterial ??=
FFIMaterial(Material_createGridMaterial(app.engine), app);
final asset = await withPointerCallback<TSceneAsset>((cb) =>
SceneAsset_createGridRenderThread(
app.engine, _gridMaterial!.getNativeHandle(), cb));
_overlay = GridOverlay(asset, app, animationManager);
var materialInstance = await _overlay!.getMaterialInstanceAt();
await materialInstance.setParameterFloat3("gridColor", 0.1, 0.1, 0.1);
await materialInstance
.setTransparencyMode(TransparencyMode.TWO_PASSES_TWO_SIDES);
await materialInstance.setCullingMode(CullingMode.NONE);
await materialInstance.setParameterFloat3("gridColor", 0.3, 0.35, 0.3);
final ffiAsset =
FFIAsset(asset, FilamentApp.instance as FFIFilamentApp, nullptr);
await FilamentApp.instance!.setPriority(ffiAsset.entity, 0);
for (final child in await ffiAsset.getChildEntities()) {
await FilamentApp.instance!.setPriority(child, 7);
}
// await materialInstance.setParameterFloat("distance", 10.0);
}
return _overlay!;
}
///
///
///
@override
Future<FFIAsset> createInstance(
{List<MaterialInstance>? materialInstances = null}) async {
throw Exception(
"Only a single instance of the grid overlay can be created");
}
}

View File

@@ -117,7 +117,7 @@ abstract class ThermionAsset {
/// call [Scene.add].
///
Future<ThermionAsset> createInstance(
{covariant List<MaterialInstance>? materialInstances = null});
{List<MaterialInstance>? materialInstances = null});
///
/// Returns the number of instances associated with this asset.

View File

@@ -7,7 +7,6 @@ import 'package:thermion_dart/thermion_dart.dart';
typedef PointerEventDetails = (Vector2 localPosition, Vector2 delta);
abstract class InputHandlerDelegate {
Future handle(List<InputEvent> events) async {
// noop, override to implement
}
@@ -36,34 +35,48 @@ class DelegateInputHandler implements InputHandler {
bool _ready = false;
bool _processing = false;
DelegateInputHandler(
{required this.viewer, required this.delegates, this.batch = true}) {
DelegateInputHandler({
required this.viewer,
required this.delegates,
this.batch = true,
}) {
FilamentApp.instance!.registerRequestFrameHook(process);
viewer.initialized.then((_) {
this._ready = true;
});
}
factory DelegateInputHandler.fixedOrbit(ThermionViewer viewer,
{double minimumDistance = 0.1,
Vector3? target,
InputSensitivityOptions sensitivity = const InputSensitivityOptions(),
ThermionEntity? entity}) {
return DelegateInputHandler(viewer: viewer, delegates: [
OrbitInputHandlerDelegate(viewer.view,
factory DelegateInputHandler.fixedOrbit(
ThermionViewer viewer, {
double minimumDistance = 0.1,
Vector3? target,
InputSensitivityOptions sensitivity = const InputSensitivityOptions(),
ThermionEntity? entity,
}) {
return DelegateInputHandler(
viewer: viewer,
delegates: [
OrbitInputHandlerDelegate(
viewer.view,
sensitivity: sensitivity,
minZoomDistance: minimumDistance,
maxZoomDistance: 1000.0)
]);
maxZoomDistance: 1000.0,
),
],
);
}
factory DelegateInputHandler.flight(ThermionViewer viewer,
{bool freeLook = false,
InputSensitivityOptions sensitivity = const InputSensitivityOptions(),
ThermionEntity? entity}) =>
DelegateInputHandler(viewer: viewer, delegates: [
FreeFlightInputHandlerDelegateV2(viewer.view, sensitivity: sensitivity)
]);
factory DelegateInputHandler.flight(
ThermionViewer viewer, {
bool freeLook = false,
InputSensitivityOptions sensitivity = const InputSensitivityOptions(),
ThermionEntity? entity,
}) => DelegateInputHandler(
viewer: viewer,
delegates: [
FreeFlightInputHandlerDelegateV2(viewer.view, sensitivity: sensitivity),
],
);
Future<void> process() async {
_processing = true;

View File

@@ -1,449 +0,0 @@
// ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_apia
// AUTO GENERATED FILE, DO NOT EDIT.
//
// Generated by `package:ffigen`.
// ignore_for_file: type=lint
import 'dart:ffi' as ffi;
import 'package:objective_c/objective_c.dart' as objc;
@ffi.Native<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCObject>, ffi.Pointer<ffi.Void>)>()
external ffi.Pointer<objc.ObjCObject>
_ThermionTextureSwift_protocolTrampoline_1mbt9g9(
ffi.Pointer<objc.ObjCObject> target,
ffi.Pointer<ffi.Void> arg0,
);
late final _class_ThermionTextureSwift =
objc.getClass("swift_module.ThermionTextureSwift");
late final _sel_isKindOfClass_ = objc.registerName("isKindOfClass:");
final _objc_msgSend_19nvye5 = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Bool Function(
ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>,
ffi.Pointer<objc.ObjCObject>)>>()
.asFunction<
bool Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Pointer<objc.ObjCObject>)>();
late final _sel_cvMetalTextureCache = objc.registerName("cvMetalTextureCache");
final _objc_msgSend_13yqbb6 = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Int Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>)>>()
.asFunction<
int Function(
ffi.Pointer<objc.ObjCObject>, ffi.Pointer<objc.ObjCSelector>)>();
late final _sel_setCvMetalTextureCache_ =
objc.registerName("setCvMetalTextureCache:");
final _objc_msgSend_9o8504 = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Void Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Int)>>()
.asFunction<
void Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, int)>();
/// WARNING: MTLDevice is a stub. To generate bindings for this class, include
/// MTLDevice in your config's objc-protocols list.
///
/// MTLDevice
interface class MTLDevice extends objc.ObjCProtocolBase {
MTLDevice._(ffi.Pointer<objc.ObjCObject> pointer,
{bool retain = false, bool release = false})
: super(pointer, retain: retain, release: release);
/// Constructs a [MTLDevice] that points to the same underlying object as [other].
MTLDevice.castFrom(objc.ObjCObjectBase other)
: this._(other.ref.pointer, retain: true, release: true);
/// Constructs a [MTLDevice] that wraps the given raw object pointer.
MTLDevice.castFromPointer(ffi.Pointer<objc.ObjCObject> other,
{bool retain = false, bool release = false})
: this._(other, retain: retain, release: release);
}
late final _sel_metalDevice = objc.registerName("metalDevice");
final _objc_msgSend_151sglz = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>)>>()
.asFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCObject>, ffi.Pointer<objc.ObjCSelector>)>();
late final _sel_setMetalDevice_ = objc.registerName("setMetalDevice:");
final _objc_msgSend_xtuoz7 = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Void Function(
ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>,
ffi.Pointer<objc.ObjCObject>)>>()
.asFunction<
void Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Pointer<objc.ObjCObject>)>();
late final _sel_cvMetalTexture = objc.registerName("cvMetalTexture");
late final _sel_setCvMetalTexture_ = objc.registerName("setCvMetalTexture:");
/// WARNING: MTLTexture is a stub. To generate bindings for this class, include
/// MTLTexture in your config's objc-protocols list.
///
/// MTLTexture
interface class MTLTexture extends objc.ObjCProtocolBase {
MTLTexture._(ffi.Pointer<objc.ObjCObject> pointer,
{bool retain = false, bool release = false})
: super(pointer, retain: retain, release: release);
/// Constructs a [MTLTexture] that points to the same underlying object as [other].
MTLTexture.castFrom(objc.ObjCObjectBase other)
: this._(other.ref.pointer, retain: true, release: true);
/// Constructs a [MTLTexture] that wraps the given raw object pointer.
MTLTexture.castFromPointer(ffi.Pointer<objc.ObjCObject> other,
{bool retain = false, bool release = false})
: this._(other, retain: retain, release: release);
}
late final _sel_metalTexture = objc.registerName("metalTexture");
late final _sel_setMetalTexture_ = objc.registerName("setMetalTexture:");
late final _sel_metalTextureAddress = objc.registerName("metalTextureAddress");
final _objc_msgSend_1hz7y9r = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Long Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>)>>()
.asFunction<
int Function(
ffi.Pointer<objc.ObjCObject>, ffi.Pointer<objc.ObjCSelector>)>();
late final _sel_setMetalTextureAddress_ =
objc.registerName("setMetalTextureAddress:");
final _objc_msgSend_4sp4xj = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Void Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Long)>>()
.asFunction<
void Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, int)>();
typedef instancetype = ffi.Pointer<objc.ObjCObject>;
typedef Dartinstancetype = objc.ObjCObjectBase;
late final _sel_init = objc.registerName("init");
late final _sel_initWithWidth_height_isDepth_isStencil_ =
objc.registerName("initWithWidth:height:isDepth:isStencil:");
final _objc_msgSend_1v8gk45 = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>,
ffi.Int64,
ffi.Int64,
ffi.Bool,
ffi.Bool)>>()
.asFunction<
ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, int, int, bool, bool)>();
late final _sel_destroyTexture = objc.registerName("destroyTexture");
final _objc_msgSend_1pl9qdv = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Void Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>)>>()
.asFunction<
void Function(
ffi.Pointer<objc.ObjCObject>, ffi.Pointer<objc.ObjCSelector>)>();
late final _sel_fillWithPNGImageWithImageURL_ =
objc.registerName("fillWithPNGImageWithImageURL:");
late final _sel_fillColor = objc.registerName("fillColor");
late final _sel_getTextureBytes = objc.registerName("getTextureBytes");
late final _sel_new = objc.registerName("new");
late final _sel_allocWithZone_ = objc.registerName("allocWithZone:");
final _objc_msgSend_1cwp428 = objc.msgSendPointer
.cast<
ffi.NativeFunction<
ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Pointer<objc.NSZone>)>>()
.asFunction<
ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<objc.ObjCObject>,
ffi.Pointer<objc.ObjCSelector>, ffi.Pointer<objc.NSZone>)>();
late final _sel_alloc = objc.registerName("alloc");
late final _sel_self = objc.registerName("self");
ffi.Pointer<objc.ObjCObject> _ObjCBlock_objcObjCObject_ffiVoid_fnPtrTrampoline(
ffi.Pointer<objc.ObjCBlockImpl> block, ffi.Pointer<ffi.Void> arg0) =>
block.ref.target
.cast<
ffi.NativeFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<ffi.Void> arg0)>>()
.asFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<ffi.Void>)>()(arg0);
ffi.Pointer<ffi.Void> _ObjCBlock_objcObjCObject_ffiVoid_fnPtrCallable =
ffi.Pointer.fromFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCBlockImpl>, ffi.Pointer<ffi.Void>)>(
_ObjCBlock_objcObjCObject_ffiVoid_fnPtrTrampoline)
.cast();
ffi.Pointer<objc.ObjCObject>
_ObjCBlock_objcObjCObject_ffiVoid_closureTrampoline(
ffi.Pointer<objc.ObjCBlockImpl> block,
ffi.Pointer<ffi.Void> arg0) =>
(objc.getBlockClosure(block) as ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<ffi.Void>))(arg0);
ffi.Pointer<ffi.Void> _ObjCBlock_objcObjCObject_ffiVoid_closureCallable =
ffi.Pointer.fromFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCBlockImpl>, ffi.Pointer<ffi.Void>)>(
_ObjCBlock_objcObjCObject_ffiVoid_closureTrampoline)
.cast();
/// Construction methods for `objc.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>`.
abstract final class ObjCBlock_objcObjCObject_ffiVoid {
/// Returns a block that wraps the given raw block pointer.
static objc
.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>
castFromPointer(ffi.Pointer<objc.ObjCBlockImpl> pointer,
{bool retain = false, bool release = false}) =>
objc.ObjCBlock<
ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>(
pointer,
retain: retain,
release: release);
/// Creates a block from a C function pointer.
///
/// This block must be invoked by native code running on the same thread as
/// the isolate that registered it. Invoking the block on the wrong thread
/// will result in a crash.
static objc.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>
fromFunctionPointer(
ffi.Pointer<
ffi.NativeFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<ffi.Void> arg0)>>
ptr) =>
objc.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>(
objc.newPointerBlock(_ObjCBlock_objcObjCObject_ffiVoid_fnPtrCallable, ptr.cast()),
retain: false,
release: true);
/// Creates a block from a Dart function.
///
/// This block must be invoked by native code running on the same thread as
/// the isolate that registered it. Invoking the block on the wrong thread
/// will result in a crash.
///
/// If `keepIsolateAlive` is true, this block will keep this isolate alive
/// until it is garbage collected by both Dart and ObjC.
static objc
.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>
fromFunction(objc.ObjCObjectBase Function(ffi.Pointer<ffi.Void>) fn,
{bool keepIsolateAlive = true}) =>
objc.ObjCBlock<
ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>(
objc.newClosureBlock(
_ObjCBlock_objcObjCObject_ffiVoid_closureCallable,
(ffi.Pointer<ffi.Void> arg0) =>
fn(arg0).ref.retainAndAutorelease(),
keepIsolateAlive),
retain: false,
release: true);
}
/// Call operator for `objc.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)>`.
extension ObjCBlock_objcObjCObject_ffiVoid_CallExtension on objc
.ObjCBlock<ffi.Pointer<objc.ObjCObject> Function(ffi.Pointer<ffi.Void>)> {
objc.ObjCObjectBase call(ffi.Pointer<ffi.Void> arg0) => objc.ObjCObjectBase(
ref.pointer.ref.invoke
.cast<
ffi.NativeFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCBlockImpl> block,
ffi.Pointer<ffi.Void> arg0)>>()
.asFunction<
ffi.Pointer<objc.ObjCObject> Function(
ffi.Pointer<objc.ObjCBlockImpl>,
ffi.Pointer<ffi.Void>)>()(ref.pointer, arg0),
retain: true,
release: true);
}
late final _sel_retain = objc.registerName("retain");
late final _sel_autorelease = objc.registerName("autorelease");
/// ThermionTextureSwift
class ThermionTextureSwift extends objc.NSObject {
ThermionTextureSwift._(ffi.Pointer<objc.ObjCObject> pointer,
{bool retain = false, bool release = false})
: super.castFromPointer(pointer, retain: retain, release: release);
/// Constructs a [ThermionTextureSwift] that points to the same underlying object as [other].
ThermionTextureSwift.castFrom(objc.ObjCObjectBase other)
: this._(other.ref.pointer, retain: true, release: true);
/// Constructs a [ThermionTextureSwift] that wraps the given raw object pointer.
ThermionTextureSwift.castFromPointer(ffi.Pointer<objc.ObjCObject> other,
{bool retain = false, bool release = false})
: this._(other, retain: retain, release: release);
/// Returns whether [obj] is an instance of [ThermionTextureSwift].
static bool isInstance(objc.ObjCObjectBase obj) {
return _objc_msgSend_19nvye5(
obj.ref.pointer, _sel_isKindOfClass_, _class_ThermionTextureSwift);
}
/// cvMetalTextureCache
int get cvMetalTextureCache {
return _objc_msgSend_13yqbb6(this.ref.pointer, _sel_cvMetalTextureCache);
}
/// setCvMetalTextureCache:
set cvMetalTextureCache(int value) {
_objc_msgSend_9o8504(this.ref.pointer, _sel_setCvMetalTextureCache_, value);
}
/// metalDevice
MTLDevice? get metalDevice {
final _ret = _objc_msgSend_151sglz(this.ref.pointer, _sel_metalDevice);
return _ret.address == 0
? null
: MTLDevice.castFromPointer(_ret, retain: true, release: true);
}
/// setMetalDevice:
set metalDevice(MTLDevice? value) {
_objc_msgSend_xtuoz7(this.ref.pointer, _sel_setMetalDevice_,
value?.ref.pointer ?? ffi.nullptr);
}
/// cvMetalTexture
int get cvMetalTexture {
return _objc_msgSend_13yqbb6(this.ref.pointer, _sel_cvMetalTexture);
}
/// setCvMetalTexture:
set cvMetalTexture(int value) {
_objc_msgSend_9o8504(this.ref.pointer, _sel_setCvMetalTexture_, value);
}
/// metalTexture
MTLTexture? get metalTexture {
final _ret = _objc_msgSend_151sglz(this.ref.pointer, _sel_metalTexture);
return _ret.address == 0
? null
: MTLTexture.castFromPointer(_ret, retain: true, release: true);
}
/// setMetalTexture:
set metalTexture(MTLTexture? value) {
_objc_msgSend_xtuoz7(this.ref.pointer, _sel_setMetalTexture_,
value?.ref.pointer ?? ffi.nullptr);
}
/// metalTextureAddress
int get metalTextureAddress {
return _objc_msgSend_1hz7y9r(this.ref.pointer, _sel_metalTextureAddress);
}
/// setMetalTextureAddress:
set metalTextureAddress(int value) {
_objc_msgSend_4sp4xj(this.ref.pointer, _sel_setMetalTextureAddress_, value);
}
/// init
ThermionTextureSwift init() {
final _ret =
_objc_msgSend_151sglz(this.ref.retainAndReturnPointer(), _sel_init);
return ThermionTextureSwift.castFromPointer(_ret,
retain: false, release: true);
}
/// initWithWidth:height:isDepth:isStencil:
ThermionTextureSwift initWithWidth_height_isDepth_isStencil_(
int width, int height, bool isDepth, bool isStencil) {
final _ret = _objc_msgSend_1v8gk45(
this.ref.retainAndReturnPointer(),
_sel_initWithWidth_height_isDepth_isStencil_,
width,
height,
isDepth,
isStencil);
return ThermionTextureSwift.castFromPointer(_ret,
retain: false, release: true);
}
/// destroyTexture
void destroyTexture() {
_objc_msgSend_1pl9qdv(this.ref.pointer, _sel_destroyTexture);
}
/// fillWithPNGImageWithImageURL:
bool fillWithPNGImageWithImageURL_(objc.NSURL imageURL) {
return _objc_msgSend_19nvye5(this.ref.pointer,
_sel_fillWithPNGImageWithImageURL_, imageURL.ref.pointer);
}
/// fillColor
void fillColor() {
_objc_msgSend_1pl9qdv(this.ref.pointer, _sel_fillColor);
}
/// getTextureBytes
objc.NSData? getTextureBytes() {
final _ret = _objc_msgSend_151sglz(this.ref.pointer, _sel_getTextureBytes);
return _ret.address == 0
? null
: objc.NSData.castFromPointer(_ret, retain: true, release: true);
}
/// new
static ThermionTextureSwift new$() {
final _ret = _objc_msgSend_151sglz(_class_ThermionTextureSwift, _sel_new);
return ThermionTextureSwift.castFromPointer(_ret,
retain: false, release: true);
}
/// allocWithZone:
static ThermionTextureSwift allocWithZone_(ffi.Pointer<objc.NSZone> zone) {
final _ret = _objc_msgSend_1cwp428(
_class_ThermionTextureSwift, _sel_allocWithZone_, zone);
return ThermionTextureSwift.castFromPointer(_ret,
retain: false, release: true);
}
/// alloc
static ThermionTextureSwift alloc() {
final _ret = _objc_msgSend_151sglz(_class_ThermionTextureSwift, _sel_alloc);
return ThermionTextureSwift.castFromPointer(_ret,
retain: false, release: true);
}
/// self
ThermionTextureSwift self$1() {
final _ret = _objc_msgSend_151sglz(this.ref.pointer, _sel_self);
return ThermionTextureSwift.castFromPointer(_ret,
retain: true, release: true);
}
/// retain
ThermionTextureSwift retain() {
final _ret = _objc_msgSend_151sglz(this.ref.pointer, _sel_retain);
return ThermionTextureSwift.castFromPointer(_ret,
retain: true, release: true);
}
/// autorelease
ThermionTextureSwift autorelease() {
final _ret = _objc_msgSend_151sglz(this.ref.pointer, _sel_autorelease);
return ThermionTextureSwift.castFromPointer(_ret,
retain: true, release: true);
}
/// Returns a new instance of ThermionTextureSwift constructed with the default `new` method.
factory ThermionTextureSwift() => new$();
}

View File

@@ -1,63 +0,0 @@
#include <stdint.h>
#import <Foundation/Foundation.h>
#import <objc/message.h>
#import "../../../native/include/generated/ThermionTextureSwiftObjCAPI.h"
#if !__has_feature(objc_arc)
#error "This file must be compiled with ARC enabled"
#endif
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"
typedef struct {
int64_t version;
void* (*newWaiter)(void);
void (*awaitWaiter)(void*);
void* (*currentIsolate)(void);
void (*enterIsolate)(void*);
void (*exitIsolate)(void);
int64_t (*getMainPortId)(void);
bool (*getCurrentThreadOwnsIsolate)(int64_t);
} DOBJC_Context;
id objc_retainBlock(id);
#define BLOCKING_BLOCK_IMPL(ctx, BLOCK_SIG, INVOKE_DIRECT, INVOKE_LISTENER) \
assert(ctx->version >= 1); \
void* targetIsolate = ctx->currentIsolate(); \
int64_t targetPort = ctx->getMainPortId == NULL ? 0 : ctx->getMainPortId(); \
return BLOCK_SIG { \
void* currentIsolate = ctx->currentIsolate(); \
bool mayEnterIsolate = \
currentIsolate == NULL && \
ctx->getCurrentThreadOwnsIsolate != NULL && \
ctx->getCurrentThreadOwnsIsolate(targetPort); \
if (currentIsolate == targetIsolate || mayEnterIsolate) { \
if (mayEnterIsolate) { \
ctx->enterIsolate(targetIsolate); \
} \
INVOKE_DIRECT; \
if (mayEnterIsolate) { \
ctx->exitIsolate(); \
} \
} else { \
void* waiter = ctx->newWaiter(); \
INVOKE_LISTENER; \
ctx->awaitWaiter(waiter); \
} \
};
Protocol* _ThermionTextureSwift_MTLDevice(void) { return @protocol(MTLDevice); }
Protocol* _ThermionTextureSwift_MTLTexture(void) { return @protocol(MTLTexture); }
typedef id (^ProtocolTrampoline)(void * sel);
__attribute__((visibility("default"))) __attribute__((used))
id _ThermionTextureSwift_protocolTrampoline_1mbt9g9(id target, void * sel) {
return ((ProtocolTrampoline)((id (*)(id, SEL, SEL))objc_msgSend)(target, @selector(getDOBJCDartProtocolMethodForSelector:), sel))(sel);
}
#undef BLOCKING_BLOCK_IMPL
#pragma clang diagnostic pop

View File

@@ -502,8 +502,171 @@ class GeometryHelper {
return Geometry(vertices, indices, normals: _normals, uvs: _uvs);
}
static Geometry camera({
double bodyWidth = 0.6, // X-axis (medium width)
double bodyHeight = 0.7, // Y-axis (medium height)
double bodyDepth = 1.4, // Z-axis (LONG dimension - camera body extends back)
double lensRadius = 0.3,
double lensLength = 0.4,
bool normals = true,
bool uvs = true,
}) {
List<double> verticesList = [];
List<double> normalsList = [];
List<double> uvsList = [];
List<int> indices = [];
static Geometry wireframeCamera({
// Helper function to add a vertex with normal and UV
void addVertex(double x, double y, double z, double nx, double ny, double nz, double u, double v) {
verticesList.addAll([x, y, z]);
if (normals) normalsList.addAll([nx, ny, nz]);
if (uvs) uvsList.addAll([u, v]);
}
int currentIndex = 0;
// === CAMERA BODY (Rectangular box) ===
// Now: width=1.0, height=0.6, depth=1.4 (long)
// The front face (Z=+halfDepth) is the short face where lens attaches
double halfWidth = bodyWidth / 2; // 0.5 (medium)
double halfHeight = bodyHeight / 2; // 0.3 (short)
double halfDepth = bodyDepth / 2; // 0.7 (long - extends backward)
// Front face (SHORT face - where lens attaches) - Z = +halfDepth
addVertex(-halfWidth, -halfHeight, halfDepth, 0, 0, 1, 0, 0); // 0
addVertex(halfWidth, -halfHeight, halfDepth, 0, 0, 1, 1, 0); // 1
addVertex(halfWidth, halfHeight, halfDepth, 0, 0, 1, 1, 1); // 2
addVertex(-halfWidth, halfHeight, halfDepth, 0, 0, 1, 0, 1); // 3
// Back face (SHORT face) - Z = -halfDepth
addVertex(halfWidth, -halfHeight, -halfDepth, 0, 0, -1, 0, 0); // 4
addVertex(-halfWidth, -halfHeight, -halfDepth, 0, 0, -1, 1, 0); // 5
addVertex(-halfWidth, halfHeight, -halfDepth, 0, 0, -1, 1, 1); // 6
addVertex(halfWidth, halfHeight, -halfDepth, 0, 0, -1, 0, 1); // 7
// Top face (LONG face) - Y = +halfHeight
addVertex(-halfWidth, halfHeight, halfDepth, 0, 1, 0, 0, 0); // 8
addVertex(halfWidth, halfHeight, halfDepth, 0, 1, 0, 1, 0); // 9
addVertex(halfWidth, halfHeight, -halfDepth, 0, 1, 0, 1, 1); // 10
addVertex(-halfWidth, halfHeight, -halfDepth, 0, 1, 0, 0, 1); // 11
// Bottom face (LONG face) - Y = -halfHeight
addVertex(-halfWidth, -halfHeight, -halfDepth, 0, -1, 0, 0, 0); // 12
addVertex(halfWidth, -halfHeight, -halfDepth, 0, -1, 0, 1, 0); // 13
addVertex(halfWidth, -halfHeight, halfDepth, 0, -1, 0, 1, 1); // 14
addVertex(-halfWidth, -halfHeight, halfDepth, 0, -1, 0, 0, 1); // 15
// Right face (LONG face) - X = +halfWidth
addVertex(halfWidth, -halfHeight, halfDepth, 1, 0, 0, 0, 0); // 16
addVertex(halfWidth, -halfHeight, -halfDepth, 1, 0, 0, 1, 0); // 17
addVertex(halfWidth, halfHeight, -halfDepth, 1, 0, 0, 1, 1); // 18
addVertex(halfWidth, halfHeight, halfDepth, 1, 0, 0, 0, 1); // 19
// Left face (LONG face) - X = -halfWidth
addVertex(-halfWidth, -halfHeight, -halfDepth, -1, 0, 0, 0, 0); // 20
addVertex(-halfWidth, -halfHeight, halfDepth, -1, 0, 0, 1, 0); // 21
addVertex(-halfWidth, halfHeight, halfDepth, -1, 0, 0, 1, 1); // 22
addVertex(-halfWidth, halfHeight, -halfDepth, -1, 0, 0, 0, 1); // 23
// Body indices
List<int> bodyIndices = [
// 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
];
indices.addAll(bodyIndices);
currentIndex = 24;
// === CONICAL LENS ===
int segments = 16;
double lensApexZ = -halfDepth; // Apex touches the front face (short face)
double lensBaseZ = -halfDepth - lensLength; // Base extends outward along Z-axis
// Lens apex (tip of the cone - touching the camera body at center of front face)
addVertex(0, 0, lensApexZ, 0, 0, -1, 0.5, 0);
int apexIndex = currentIndex;
currentIndex++;
// Lens base circle (the wide part extending outward)
List<int> baseIndices = [];
for (int i = 0; i < segments; i++) {
double theta = i * 2 * pi / segments;
double x = lensRadius * cos(theta);
double y = lensRadius * sin(theta);
// Calculate normal for cone side (pointing outward from cone surface)
double normalX = x / lensRadius; // Normalized radial component
double normalY = y / lensRadius;
double normalZ = lensRadius / lensLength; // Axial component based on cone slope
// Normalize the normal vector
double normalLength = sqrt(normalX * normalX + normalY * normalY + normalZ * normalZ);
normalX /= normalLength;
normalY /= normalLength;
normalZ /= normalLength;
addVertex(x, y, lensBaseZ, normalX, normalY, normalZ, i / segments, 1);
baseIndices.add(currentIndex);
currentIndex++;
}
// Create cone side triangles
for (int i = 0; i < segments; i++) {
int current = baseIndices[i];
int next = baseIndices[(i + 1) % segments];
// Triangle from apex to base edge (counter-clockwise when viewed from outside)
indices.addAll([apexIndex, next, current]);
}
// === LENS BASE (flat circular face at the wide end) ===
// Center of lens base
addVertex(0, 0, lensBaseZ, 0, 0, 1, 0.5, 0.5);
int baseCenterIndex = currentIndex;
currentIndex++;
// Base circle vertices (separate from cone vertices for proper normals)
List<int> baseFaceIndices = [];
for (int i = 0; i < segments; i++) {
double theta = i * 2 * pi / segments;
double x = lensRadius * cos(theta);
double y = lensRadius * sin(theta);
double u = 0.5 + 0.5 * cos(theta);
double v = 0.5 + 0.5 * sin(theta);
addVertex(x, y, lensBaseZ, 0, 0, 1, u, v);
baseFaceIndices.add(currentIndex);
currentIndex++;
}
// Create base face triangles (facing outward from camera)
for (int i = 0; i < segments; i++) {
int current = baseFaceIndices[i];
int next = baseFaceIndices[(i + 1) % segments];
// Triangle from center to edge (counter-clockwise when viewed from outside)
indices.addAll([baseCenterIndex, current, next]);
}
Float32List vertices = Float32List.fromList(verticesList);
Float32List? _normals = normals ? Float32List.fromList(normalsList) : null;
Float32List? _uvs = uvs ? Float32List.fromList(uvsList) : null;
return Geometry(vertices, Uint16List.fromList(indices), normals: _normals, uvs: _uvs);
}
static Geometry wireframeCamera({
double sphereRadius = 0.2,
double frustumDistance = 1.0,
double frustumNear = 0.5,

View File

@@ -394,6 +394,7 @@ class ThermionViewerFFI extends ThermionViewer {
}
if (_skyboxTextureUploadComplete != null) {
await FilamentApp.instance!.flush();
await _skyboxTextureUploadComplete;
_skyboxTextureUploadComplete = null;
}
@@ -414,6 +415,7 @@ class ThermionViewerFFI extends ThermionViewer {
await ibl.destroy();
}
if (_iblTextureUploadComplete != null) {
await FilamentApp.instance!.flush();
await _iblTextureUploadComplete!;
_iblTextureUploadComplete = null;
}
@@ -691,7 +693,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
///
Future setGridOverlayVisibility(bool visible) async {
_grid ??= _grid = await GridOverlay.create(app, animationManager);
_grid ??= await GridOverlay.create(app, animationManager);
if (visible) {
await scene.add(_grid!);

View File

@@ -83,7 +83,8 @@ abstract class ThermionViewer {
Future clearBackgroundImage({bool destroy = false});
///
/// Sets the color for the background plane (positioned at the maximum depth, i.e. behind all other objects including the skybox).
/// 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);
@@ -343,13 +344,14 @@ abstract class ThermionViewer {
int getCameraCount();
///
/// Adds the asset to the scene, meaning the asset will be rendered/visible.
/// Adds the asset to the scene. All renderable entities attached to
/// the asset will be visible.
///
Future addToScene(covariant ThermionAsset asset);
///
/// Removes the asset from the scene, meaning the asset will not be rendered/visible.
/// The asset itself will remain valid.
/// Removes the asset from the scene. None of the renderable entities
/// attached to the asset will be visible, but the asset itself remains valid.
///
Future removeFromScene(covariant ThermionAsset asset);
}

View File

@@ -25,7 +25,6 @@
#pragma comment(lib, "dracodec.lib")
#pragma comment(lib, "ibl.lib")
#pragma comment(lib, "ktxreader.lib")
#pragma comment(lib, "png.lib")
#pragma comment(lib, "z.lib")
#pragma comment(lib, "stb.lib")
#pragma comment(lib, "uberzlib.lib")

View File

@@ -1,5 +1,9 @@
#pragma once
#ifdef _WIN32
#include "ThermionWin32.h"
#endif
#ifdef __cplusplus
namespace thermion {
extern "C"
@@ -16,35 +20,35 @@ enum TProjection {
typedef enum TProjection TProjection;
// Camera methods
void Camera_setExposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
double4x4 Camera_getModelMatrix(TCamera *const camera);
double4x4 Camera_getViewMatrix(TCamera *const camera);
double4x4 Camera_getProjectionMatrix(TCamera *const camera);
double4x4 Camera_getCullingProjectionMatrix(TCamera *const camera);
void Camera_getFrustum(TCamera *camera, double* out);
void Camera_setProjectionMatrix(TCamera *camera, double *matrix, double near, double far);
void Camera_setProjectionFromFov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
double Camera_getFocalLength(TCamera *const camera);
double4x4 Camera_getViewMatrix(TCamera *const camera);
double4x4 Camera_getModelMatrix(TCamera* camera);
void Camera_lookAt(TCamera* camera, double3 eye, double3 focus, double3 up);
EMSCRIPTEN_KEEPALIVE void Camera_setExposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getProjectionMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getCullingProjectionMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE void Camera_getFrustum(TCamera *camera, double* out);
EMSCRIPTEN_KEEPALIVE void Camera_setProjectionMatrix(TCamera *camera, double *matrix, double near, double far);
EMSCRIPTEN_KEEPALIVE void Camera_setProjectionFromFov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const camera);
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera* camera);
EMSCRIPTEN_KEEPALIVE void Camera_lookAt(TCamera* camera, double3 eye, double3 focus, double3 up);
double Camera_getNear(TCamera *camera);
double Camera_getCullingFar(TCamera *camera);
float Camera_getFov(TCamera *camera, bool horizontal);
double Camera_getFocusDistance(TCamera *camera);
void Camera_setFocusDistance(TCamera *camera, float focusDistance);
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *camera);
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *camera);
EMSCRIPTEN_KEEPALIVE float Camera_getFov(TCamera *camera, bool horizontal);
EMSCRIPTEN_KEEPALIVE double Camera_getFocusDistance(TCamera *camera);
EMSCRIPTEN_KEEPALIVE void Camera_setFocusDistance(TCamera *camera, float focusDistance);
void Camera_setCustomProjectionWithCulling(
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(
TCamera* camera,
double4x4 projectionMatrix,
double near,
double far
);
void Camera_setModelMatrix(TCamera* camera, double *tModelMatrix);
void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength);
EntityId Camera_getEntity(TCamera* camera);
void Camera_setProjection(TCamera *const tCamera, TProjection projection, double left, double right,
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera* camera, double *tModelMatrix);
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength);
EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera* camera);
EMSCRIPTEN_KEEPALIVE void Camera_setProjection(TCamera *const tCamera, TProjection projection, double left, double right,
double bottom, double top,
double near, double far);

View File

@@ -16,16 +16,16 @@ namespace thermion
typedef int32_t EntityId;
typedef void (*FilamentRenderCallback)(void *const owner);
void RenderThread_create();
void RenderThread_destroy();
void RenderThread_requestFrameAsync();
void RenderThread_setRenderTicker(TRenderTicker *tRenderTicker);
void RenderThread_addTask(void (*task)());
EMSCRIPTEN_KEEPALIVE void RenderThread_create();
EMSCRIPTEN_KEEPALIVE void RenderThread_destroy();
EMSCRIPTEN_KEEPALIVE void RenderThread_requestFrameAsync();
EMSCRIPTEN_KEEPALIVE void RenderThread_setRenderTicker(TRenderTicker *tRenderTicker);
EMSCRIPTEN_KEEPALIVE void RenderThread_addTask(void (*task)());
void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos, uint32_t requestId, VoidCallback onComplete);
void AnimationManager_createRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)(TAnimationManager *));
EMSCRIPTEN_KEEPALIVE void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void AnimationManager_createRenderThread(TEngine *tEngine, TScene *tScene, void (*onComplete)(TAnimationManager *));
void Engine_createRenderThread(
EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread(
TBackend backend,
void* platform,
void* sharedContext,
@@ -33,22 +33,22 @@ namespace thermion
bool disableHandleUseAfterFreeCheck,
void (*onComplete)(TEngine *)
);
void Engine_createRendererRenderThread(TEngine *tEngine, void (*onComplete)(TRenderer *));
void Engine_createSwapChainRenderThread(TEngine *tEngine, void *window, uint64_t flags, void (*onComplete)(TSwapChain *));
void Engine_createHeadlessSwapChainRenderThread(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags, void (*onComplete)(TSwapChain *));
void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *));
void Engine_createViewRenderThread(TEngine *tEngine, void (*onComplete)(TView *));
void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *));
void Engine_destroyRenderThread(TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, uint32_t requestId, VoidCallback onComplete);
void Engine_destroyViewRenderThread(TEngine *tEngine, TView *tView, uint32_t requestId, VoidCallback onComplete);
void Engine_destroySceneRenderThread(TEngine *tEngine, TScene *tScene, uint32_t requestId, VoidCallback onComplete);
void Engine_destroyColorGradingRenderThread(TEngine *tEngine, TColorGrading *tColorGrading, uint32_t requestId, VoidCallback onComplete);
void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, uint32_t requestId, VoidCallback onComplete);
void Engine_destroyMaterialInstanceRenderThread(TEngine *tEngine, TMaterialInstance *tMaterialInstance, uint32_t requestId, VoidCallback onComplete);
void Engine_destroySkyboxRenderThread(TEngine *tEngine, TSkybox *tSkybox, uint32_t requestId, VoidCallback onComplete);
void Engine_destroyIndirectLightRenderThread(TEngine *tEngine, TIndirectLight *tIndirectLight, uint32_t requestId, VoidCallback onComplete);
void Texture_buildRenderThread(TEngine *engine,
EMSCRIPTEN_KEEPALIVE void Engine_createRendererRenderThread(TEngine *tEngine, void (*onComplete)(TRenderer *));
EMSCRIPTEN_KEEPALIVE void Engine_createSwapChainRenderThread(TEngine *tEngine, void *window, uint64_t flags, void (*onComplete)(TSwapChain *));
EMSCRIPTEN_KEEPALIVE void Engine_createHeadlessSwapChainRenderThread(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags, void (*onComplete)(TSwapChain *));
EMSCRIPTEN_KEEPALIVE void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *));
EMSCRIPTEN_KEEPALIVE void Engine_createViewRenderThread(TEngine *tEngine, void (*onComplete)(TView *));
EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Engine_destroyRenderThread(TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyViewRenderThread(TEngine *tEngine, TView *tView, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroySceneRenderThread(TEngine *tEngine, TScene *tScene, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyColorGradingRenderThread(TEngine *tEngine, TColorGrading *tColorGrading, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialInstanceRenderThread(TEngine *tEngine, TMaterialInstance *tMaterialInstance, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroySkyboxRenderThread(TEngine *tEngine, TSkybox *tSkybox, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyIndirectLightRenderThread(TEngine *tEngine, TIndirectLight *tIndirectLight, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Texture_buildRenderThread(TEngine *engine,
uint32_t width,
uint32_t height,
uint32_t depth,
@@ -59,25 +59,25 @@ namespace thermion
TTextureFormat format,
void (*onComplete)(TTexture*)
);
void Texture_generateMipMapsRenderThread(TTexture *tTexture, TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
void Ktx1Reader_createTextureRenderThread(TEngine *tEngine, TKtx1Bundle *tBundle, uint32_t requestId, VoidCallback onTextureUploadComplete, void (*onComplete)(TTexture *));
EMSCRIPTEN_KEEPALIVE void Texture_generateMipMapsRenderThread(TTexture *tTexture, TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Ktx1Reader_createTextureRenderThread(TEngine *tEngine, TKtx1Bundle *tBundle, uint32_t requestId, VoidCallback onTextureUploadComplete, void (*onComplete)(TTexture *));
void Engine_destroyTextureRenderThread(TEngine *engine, TTexture* tTexture, uint32_t requestId, VoidCallback onComplete);
void Engine_createFenceRenderThread(TEngine *tEngine, void (*onComplete)(TFence*));
void Fence_waitAndDestroyRenderThread(TFence *tFence, uint32_t requestId, VoidCallback onComplete);
void Engine_destroyFenceRenderThread(TEngine *tEngine, TFence *tFence, uint32_t requestId, VoidCallback onComplete);
void Engine_flushAndWaitRenderThread(TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
void Engine_executeRenderThread(TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
void Engine_buildSkyboxRenderThread(TEngine *tEngine, TTexture *tTexture, void (*onComplete)(TSkybox *));
void Engine_buildIndirectLightFromIrradianceTextureRenderThread(TEngine *tEngine, TTexture *tReflectionsTexture, TTexture* tIrradianceTexture, float intensity, void (*onComplete)(TIndirectLight *));
void Engine_buildIndirectLightFromIrradianceHarmonicsRenderThread(TEngine *tEngine, TTexture *tReflectionsTexture, float *harmonics, float intensity, void (*onComplete)(TIndirectLight *));
EMSCRIPTEN_KEEPALIVE void Engine_destroyTextureRenderThread(TEngine *engine, TTexture* tTexture, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_createFenceRenderThread(TEngine *tEngine, void (*onComplete)(TFence*));
EMSCRIPTEN_KEEPALIVE void Fence_waitAndDestroyRenderThread(TFence *tFence, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_destroyFenceRenderThread(TEngine *tEngine, TFence *tFence, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_flushAndWaitRenderThread(TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_executeRenderThread(TEngine *tEngine, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Engine_buildSkyboxRenderThread(TEngine *tEngine, TTexture *tTexture, void (*onComplete)(TSkybox *));
EMSCRIPTEN_KEEPALIVE void Engine_buildIndirectLightFromIrradianceTextureRenderThread(TEngine *tEngine, TTexture *tReflectionsTexture, TTexture* tIrradianceTexture, float intensity, void (*onComplete)(TIndirectLight *));
EMSCRIPTEN_KEEPALIVE void Engine_buildIndirectLightFromIrradianceHarmonicsRenderThread(TEngine *tEngine, TTexture *tReflectionsTexture, float *harmonics, float intensity, void (*onComplete)(TIndirectLight *));
void Renderer_setClearOptionsRenderThread(TRenderer *tRenderer, double clearR, double clearG, double clearB, double clearA, uint8_t clearStencil, bool clear, bool discard, uint32_t requestId, VoidCallback onComplete);
void Renderer_beginFrameRenderThread(TRenderer *tRenderer, TSwapChain *tSwapChain, uint64_t frameTimeInNanos, void (*onComplete)(bool));
void Renderer_endFrameRenderThread(TRenderer *tRenderer, uint32_t requestId, VoidCallback onComplete);
void Renderer_renderRenderThread(TRenderer *tRenderer, TView *tView, uint32_t requestId, VoidCallback onComplete);
void Renderer_renderStandaloneViewRenderThread(TRenderer *tRenderer, TView *tView, uint32_t requestId, VoidCallback onComplete);
void Renderer_readPixelsRenderThread(
EMSCRIPTEN_KEEPALIVE void Renderer_setClearOptionsRenderThread(TRenderer *tRenderer, double clearR, double clearG, double clearB, double clearA, uint8_t clearStencil, bool clear, bool discard, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_beginFrameRenderThread(TRenderer *tRenderer, TSwapChain *tSwapChain, uint64_t frameTimeInNanos, void (*onComplete)(bool));
EMSCRIPTEN_KEEPALIVE void Renderer_endFrameRenderThread(TRenderer *tRenderer, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_renderRenderThread(TRenderer *tRenderer, TView *tView, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_renderStandaloneViewRenderThread(TRenderer *tRenderer, TView *tView, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Renderer_readPixelsRenderThread(
TRenderer *tRenderer,
uint32_t width, uint32_t height, uint32_t xOffset, uint32_t yOffset,
TRenderTarget *tRenderTarget,
@@ -87,29 +87,29 @@ namespace thermion
size_t outLength,
uint32_t requestId, VoidCallback onComplete);
void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *));
void Material_createImageMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
void Material_createGizmoMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
void Material_createOutlineMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Material_createInstanceRenderThread(TMaterial *tMaterial, void (*onComplete)(TMaterialInstance *));
EMSCRIPTEN_KEEPALIVE void Material_createImageMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Material_createGizmoMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
EMSCRIPTEN_KEEPALIVE void Material_createOutlineMaterialRenderThread(TEngine *tEngine, void (*onComplete)(TMaterial *));
void ColorGrading_createRenderThread(TEngine *tEngine, TToneMapping toneMapping, void (*callback)(TColorGrading *));
void View_pickRenderThread(TView *tView, uint32_t requestId, uint32_t x, uint32_t y, PickCallback callback);
void View_setColorGradingRenderThread(TView *tView, TColorGrading *tColorGrading, uint32_t requestId, VoidCallback onComplete);
void View_setBloomRenderThread(TView *tView, bool enabled, double strength, uint32_t requestId, VoidCallback onComplete);
void View_setCameraRenderThread(TView *tView, TCamera *tCamera, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void ColorGrading_createRenderThread(TEngine *tEngine, TToneMapping toneMapping, void (*callback)(TColorGrading *));
EMSCRIPTEN_KEEPALIVE void View_pickRenderThread(TView *tView, uint32_t requestId, uint32_t x, uint32_t y, PickCallback callback);
EMSCRIPTEN_KEEPALIVE void View_setColorGradingRenderThread(TView *tView, TColorGrading *tColorGrading, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, bool enabled, double strength, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void View_setCameraRenderThread(TView *tView, TCamera *tCamera, uint32_t requestId, VoidCallback onComplete);
void SceneAsset_createGridRenderThread(TEngine *tEngine, TMaterial * tMaterial, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void SceneAsset_createGridRenderThread(TEngine *tEngine, TMaterial * tMaterial, void (*callback)(TSceneAsset *));
void SceneAsset_destroyRenderThread(TSceneAsset *tSceneAsset, uint32_t requestId, VoidCallback onComplete);
void SceneAsset_createFromFilamentAssetRenderThread(
EMSCRIPTEN_KEEPALIVE void SceneAsset_destroyRenderThread(TSceneAsset *tSceneAsset, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void SceneAsset_createFromFilamentAssetRenderThread(
TEngine *tEngine,
TGltfAssetLoader *tAssetLoader,
TNameComponentManager *tNameComponentManager,
TFilamentAsset *tFilamentAsset,
void (*onComplete)(TSceneAsset *)
);
void SceneAsset_createInstanceRenderThread(TSceneAsset *asset, TMaterialInstance **tMaterialInstances, int materialInstanceCount, void (*callback)(TSceneAsset *));
void SceneAsset_createGeometryRenderThread(
EMSCRIPTEN_KEEPALIVE void SceneAsset_createInstanceRenderThread(TSceneAsset *asset, TMaterialInstance **tMaterialInstances, int materialInstanceCount, void (*callback)(TSceneAsset *));
EMSCRIPTEN_KEEPALIVE void SceneAsset_createGeometryRenderThread(
TEngine *tEngine,
float *vertices,
uint32_t numVertices,
@@ -124,7 +124,7 @@ namespace thermion
int materialInstanceCount,
void (*callback)(TSceneAsset *)
);
void MaterialProvider_createMaterialInstanceRenderThread(
EMSCRIPTEN_KEEPALIVE void MaterialProvider_createMaterialInstanceRenderThread(
TMaterialProvider *tMaterialProvider,
bool doubleSided,
bool unlit,
@@ -166,12 +166,12 @@ namespace thermion
bool hasVolume,
void (*callback)(TMaterialInstance *));
void AnimationManager_updateBoneMatricesRenderThread(
EMSCRIPTEN_KEEPALIVE void AnimationManager_updateBoneMatricesRenderThread(
TAnimationManager *tAnimationManager,
TSceneAsset *sceneAsset,
void (*callback)(bool));
void AnimationManager_setMorphTargetWeightsRenderThread(
EMSCRIPTEN_KEEPALIVE void AnimationManager_setMorphTargetWeightsRenderThread(
TAnimationManager *tAnimationManager,
EntityId entityId,
const float *const morphData,
@@ -179,16 +179,16 @@ namespace thermion
void (*callback)(bool));
// Image methods
void Image_createEmptyRenderThread(uint32_t width, uint32_t height, uint32_t channel, void (*onComplete)(TLinearImage *));
void Image_decodeRenderThread(uint8_t* data, size_t length, const char* name, bool alpha, void (*onComplete)(TLinearImage *));
void Image_getBytesRenderThread(TLinearImage *tLinearImage, void (*onComplete)(float *));
void Image_destroyRenderThread(TLinearImage *tLinearImage, uint32_t requestId, VoidCallback onComplete);
void Image_getWidthRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
void Image_getHeightRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
void Image_getChannelsRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
EMSCRIPTEN_KEEPALIVE void Image_createEmptyRenderThread(uint32_t width, uint32_t height, uint32_t channel, void (*onComplete)(TLinearImage *));
EMSCRIPTEN_KEEPALIVE void Image_decodeRenderThread(uint8_t* data, size_t length, const char* name, bool alpha, void (*onComplete)(TLinearImage *));
EMSCRIPTEN_KEEPALIVE void Image_getBytesRenderThread(TLinearImage *tLinearImage, void (*onComplete)(float *));
EMSCRIPTEN_KEEPALIVE void Image_destroyRenderThread(TLinearImage *tLinearImage, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Image_getWidthRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
EMSCRIPTEN_KEEPALIVE void Image_getHeightRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
EMSCRIPTEN_KEEPALIVE void Image_getChannelsRenderThread(TLinearImage *tLinearImage, void (*onComplete)(uint32_t));
void Texture_loadImageRenderThread(
EMSCRIPTEN_KEEPALIVE void Texture_loadImageRenderThread(
TEngine *tEngine,
TTexture *tTexture,
TLinearImage *tImage,
@@ -197,7 +197,7 @@ namespace thermion
int level,
void (*onComplete)(bool)
);
void Texture_setImageRenderThread(
EMSCRIPTEN_KEEPALIVE void Texture_setImageRenderThread(
TEngine *tEngine,
TTexture *tTexture,
uint32_t level,
@@ -213,8 +213,8 @@ namespace thermion
uint32_t pixelDataType,
void (*onComplete)(bool)
);
void RenderTarget_getColorTextureRenderThread(TRenderTarget *tRenderTarget, void (*onComplete)(TTexture *));
void RenderTarget_createRenderThread(
EMSCRIPTEN_KEEPALIVE void RenderTarget_getColorTextureRenderThread(TRenderTarget *tRenderTarget, void (*onComplete)(TTexture *));
EMSCRIPTEN_KEEPALIVE void RenderTarget_createRenderThread(
TEngine *tEngine,
uint32_t width,
uint32_t height,
@@ -222,7 +222,7 @@ namespace thermion
TTexture *depth,
void (*onComplete)(TRenderTarget *)
);
void RenderTarget_destroyRenderThread(
EMSCRIPTEN_KEEPALIVE void RenderTarget_destroyRenderThread(
TEngine *tEngine,
TRenderTarget *tRenderTarget,
uint32_t requestId, VoidCallback onComplete
@@ -230,8 +230,8 @@ namespace thermion
// TextureSampler methods
void TextureSampler_createRenderThread(void (*onComplete)(TTextureSampler*));
void TextureSampler_createWithFilteringRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_createRenderThread(void (*onComplete)(TTextureSampler*));
EMSCRIPTEN_KEEPALIVE void TextureSampler_createWithFilteringRenderThread(
TSamplerMinFilter minFilter,
TSamplerMagFilter magFilter,
TSamplerWrapMode wrapS,
@@ -239,53 +239,53 @@ namespace thermion
TSamplerWrapMode wrapR,
void (*onComplete)(TTextureSampler*)
);
void TextureSampler_createWithComparisonRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_createWithComparisonRenderThread(
TSamplerCompareMode compareMode,
TSamplerCompareFunc compareFunc,
void (*onComplete)(TTextureSampler*)
);
void TextureSampler_setMinFilterRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMinFilterRenderThread(
TTextureSampler* sampler,
TSamplerMinFilter filter,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_setMagFilterRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setMagFilterRenderThread(
TTextureSampler* sampler,
TSamplerMagFilter filter,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_setWrapModeSRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeSRenderThread(
TTextureSampler* sampler,
TSamplerWrapMode mode,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_setWrapModeTRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeTRenderThread(
TTextureSampler* sampler,
TSamplerWrapMode mode,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_setWrapModeRRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setWrapModeRRenderThread(
TTextureSampler* sampler,
TSamplerWrapMode mode,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_setAnisotropyRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setAnisotropyRenderThread(
TTextureSampler* sampler,
double anisotropy,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_setCompareModeRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_setCompareModeRenderThread(
TTextureSampler* sampler,
TSamplerCompareMode mode,
TTextureSamplerCompareFunc func,
uint32_t requestId, VoidCallback onComplete
);
void TextureSampler_destroyRenderThread(
EMSCRIPTEN_KEEPALIVE void TextureSampler_destroyRenderThread(
TTextureSampler* sampler,
uint32_t requestId, VoidCallback onComplete
);
void AnimationManager_setBoneTransformRenderThread(
EMSCRIPTEN_KEEPALIVE void AnimationManager_setBoneTransformRenderThread(
TAnimationManager *tAnimationManager,
EntityId asset,
int skinIndex,
@@ -293,18 +293,18 @@ namespace thermion
const float *const transform,
void (*callback)(bool));
void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void AnimationManager_resetToRestPoseRenderThread(TAnimationManager *tAnimationManager, TSceneAsset *tSceneAsset, uint32_t requestId, VoidCallback onComplete);
void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, TNameComponentManager *tNameComponentManager, void (*callback)(TGltfAssetLoader *));
void GltfResourceLoader_createRenderThread(TEngine *tEngine, void (*callback)(TGltfResourceLoader *));
void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, uint32_t requestId, VoidCallback onComplete);
void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, uint32_t requestId, VoidCallback onComplete);
void GltfResourceLoader_asyncBeginLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
void GltfResourceLoader_asyncUpdateLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader);
void GltfResourceLoader_asyncGetLoadProgressRenderThread(TGltfResourceLoader *tGltfResourceLoader, void (*callback)(float));
EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, TNameComponentManager *tNameComponentManager, void (*callback)(TGltfAssetLoader *));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_createRenderThread(TEngine *tEngine, void (*callback)(TGltfResourceLoader *));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_destroyRenderThread(TEngine *tEngine, TGltfResourceLoader *tResourceLoader, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_loadResourcesRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_addResourceDataRenderThread(TGltfResourceLoader *tGltfResourceLoader, const char *uri, uint8_t *data, size_t length, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_asyncBeginLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader, TFilamentAsset *tFilamentAsset, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_asyncUpdateLoadRenderThread(TGltfResourceLoader *tGltfResourceLoader);
EMSCRIPTEN_KEEPALIVE void GltfResourceLoader_asyncGetLoadProgressRenderThread(TGltfResourceLoader *tGltfResourceLoader, void (*callback)(float));
void GltfAssetLoader_loadRenderThread(
EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_loadRenderThread(
TEngine *tEngine,
TGltfAssetLoader *tAssetLoader,
uint8_t *data,
@@ -312,8 +312,8 @@ namespace thermion
uint8_t numInstances,
void (*callback)(TFilamentAsset *)
);
void Scene_addFilamentAssetRenderThread(TScene* tScene, TFilamentAsset *tAsset, uint32_t requestId, VoidCallback onComplete);
void Gizmo_createRenderThread(
EMSCRIPTEN_KEEPALIVE void Scene_addFilamentAssetRenderThread(TScene* tScene, TFilamentAsset *tAsset, uint32_t requestId, VoidCallback onComplete);
EMSCRIPTEN_KEEPALIVE void Gizmo_createRenderThread(
TEngine *tEngine,
TGltfAssetLoader *tAssetLoader,
TGltfResourceLoader *tGltfResourceLoader,
@@ -330,4 +330,3 @@ namespace thermion
}
}
#endif

View File

@@ -8,5 +8,5 @@ GRID_PACKAGE:
GRID_GRID_OFFSET:
.int 0
GRID_GRID_SIZE:
.int 50913
.int 49793

View File

@@ -8,5 +8,5 @@ _GRID_PACKAGE:
_GRID_GRID_OFFSET:
.int 0
_GRID_GRID_SIZE:
.int 50913
.int 49793

File diff suppressed because it is too large Load Diff

View File

@@ -3,11 +3,15 @@
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t GRID_PACKAGE[];
extern int GRID_GRID_OFFSET;
extern int GRID_GRID_SIZE;
#ifdef __cplusplus
}
#endif
#define GRID_GRID_DATA (GRID_PACKAGE + GRID_GRID_OFFSET)
#endif

View File

@@ -3,11 +3,16 @@
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern const uint8_t OUTLINE_PACKAGE[];
extern int OUTLINE_OUTLINE_OFFSET;
extern int OUTLINE_OUTLINE_SIZE;
#ifdef __cplusplus
}
#endif
#define OUTLINE_OUTLINE_DATA (OUTLINE_PACKAGE + OUTLINE_OUTLINE_OFFSET)
#endif

View File

@@ -37,6 +37,10 @@ public:
MaterialInstance** getMaterialInstances() override { return &_materialInstance; }
size_t getMaterialInstanceCount() override { return 1; }
utils::Entity getEntity() override {
return _gridEntity;
}
void addAllEntities(Scene* scene) override;
void removeAllEntities(Scene* scene) override;

View File

@@ -209,10 +209,7 @@ namespace thermion
SceneAsset *GridOverlay::createInstance(MaterialInstance **materialInstances, size_t materialInstanceCount)
{
auto instance = std::make_unique<GridOverlay>(_engine, _material);
auto *raw = instance.get();
_instances.push_back(std::move(instance));
return reinterpret_cast<SceneAsset *>(raw);
return nullptr;
}
void GridOverlay::addAllEntities(Scene *scene)
@@ -250,7 +247,7 @@ namespace thermion
}
size_t GridOverlay::getChildEntityCount() {
return 1;
return 0;
}
Entity GridOverlay::findEntityByName(const char *name)

View File

@@ -85,10 +85,10 @@ EMSCRIPTEN_KEEPALIVE TFilamentAsset *GltfAssetLoader_load(
const char *const *const resourceUris = asset->getResourceUris();
const size_t resourceUriCount = asset->getResourceUriCount();
Log("glTF asset : %d resource URIs, %d instances", resourceUriCount, numInstances);
TRACE("Loading glTF asset with %d resource URIs (allocating %d reserved instances", resourceUriCount, numInstances);
for(int i = 0; i < resourceUriCount; i++) {
Log("%s", resourceUris[i]);
TRACE("%s", resourceUris[i]);
}
return reinterpret_cast<TFilamentAsset *>(asset);

View File

@@ -54,7 +54,7 @@ set(EMCC_CFLAGS ${EMCC_CFLAGS} -sSTACK_SIZE=10485760)
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sLINKABLE=1)
# set(EMCC_CFLAGS ${EMCC_CFLAGS} -sSIDE_MODULE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++17 -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=1")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++17 -Wno-invalid-specialization -DEMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES=1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")
if(CMAKE_BUILD_TYPE STREQUAL "Debug")

View File

@@ -1,11 +1,11 @@
name: thermion_dart
description: 3D rendering toolkit for Dart.
version: 0.3.0
version: 0.3.3
homepage: https://thermion.dev
repository: https://github.com/nmfisher/thermion
environment:
sdk: ">=3.5.4 <4.0.0"
sdk: ">=3.6.0-0 <4.0.0"
dependencies:
vector_math: ^2.1.2

View File

@@ -82,10 +82,6 @@ class TestHelper {
testDir = Directory("${packageUri}test").path;
outDir = Directory("$testDir/output/${dir}");
outDir.createSync(recursive: true);
if (Platform.isMacOS) {
DynamicLibrary.open('${testDir}/generated/objective_c.dylib');
DynamicLibrary.open('${testDir}/generated/libThermionTextureSwift.dylib');
}
}
///
@@ -226,6 +222,10 @@ class TestHelper {
FFIRenderTarget? renderTarget;
if (createRenderTarget) {
// if (Platform.isMacOS) {
// DynamicLibrary.open('${testDir}/generated/objective_c.dylib');
// DynamicLibrary.open('${testDir}/generated/libThermionTextureSwift.dylib');
// }
// var metalColorTexture = await createTexture(
// viewportDimensions.width, viewportDimensions.height);
// var metalDepthTexture = await createTexture(

View File

@@ -1,3 +1,25 @@
## 0.3.3
- Bump "thermion_flutter" to `0.3.3`.
## 0.3.3-pre
- **DOCS**: replace thermion_flutter README with symlink to thermion_dart README.
## 0.3.2
- Bump "thermion_flutter" to `0.3.2`.
## 0.3.1
- **FIX**: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets.
- **DOCS**: fix typo in link.
- **DOCS**: remove code from thermion_flutter README.md and point to docs/repository example instead.
## 0.3.0
- Bump "thermion_flutter" to `0.3.0`.
## 0.3.0
> Note: This release has breaking changes.

View File

@@ -1,63 +0,0 @@
![Thermion Logo](https://raw.githubusercontent.com/nmfisher/flutter_filament/f19ea9b/docs/logo.png)
<p align="center">
<a href="https://thermion.dev/quickstart">Quickstart (Flutter)</a> •
<a href="https://thermion.dev/quickstart">Documentation</a> •
<a href="https://thermion.dev/showcase">Showcase</a> •
<a href="https://dartpad.thermion.dev/">Playground</a> •
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
</p>
## Cross-platform 3D engine for Dart and Flutter.
<a href="https://pub.dev/packages/thermion_dart"><img src="https://img.shields.io/pub/v/thermion_dart?label=pub.dev&labelColor=333940&logo=dart&color=00589B" alt="pub"></a>
<a href="https://github.com/nmfisher/thermion"><img src="https://img.shields.io/github/stars/nmfisher/flutter_filament?style=flat&label=stars&labelColor=333940&color=8957e5&logo=github" alt="github"></a>
<a href="https://discord.gg/h2VdDK3EAQ"><img src="https://img.shields.io/discord/993167615587520602?logo=discord&logoColor=fff&labelColor=333940" alt="discord"></a>
<a href="https://github.com/nmfisher/thermion"><img src="https://img.shields.io/github/contributors/nmfisher/flutter_filament?logo=github&labelColor=333940" alt="contributors"></a>
### Quickstart (Flutter)
```
_thermionViewer = await ThermionFlutterPlugin.createViewer();
// Geometry and models are represented as "entities". Here, we load a glTF
// file containing a plain cube.
// By default, all paths are treated as asset paths. To load from a file
// instead, use file:// URIs.
var entity =
await _thermionViewer!.loadGlb("assets/cube.glb", keepData: true);
// Thermion uses a right-handed coordinate system where +Y is up and -Z is
// "into" the screen.
// By default, the camera is located at (0,0,0) looking at (0,0,-1); this
// would place it directly inside the cube we just loaded.
//
// Let's move the camera to (0,0,10) to ensure the cube is visible in the
// viewport.
await _thermionViewer!.setCameraPosition(0, 0, 10);
// Without a light source, your scene will be totally black. Let's load a skybox
// (a cubemap image that is rendered behind everything else in the scene)
// and an image-based indirect light that has been precomputed from the same
// skybox.
await _thermionViewer!.loadSkybox("assets/default_env_skybox.ktx");
await _thermionViewer!.loadIbl("assets/default_env_ibl.ktx");
// Finally, you need to explicitly enable rendering. Setting rendering to
// false is designed to allow you to pause rendering to conserve battery life
await _thermionViewer!.setRendering(true);
```
and then in your Flutter application:
```
@override
Widget build(BuildContext context) {
return Stack(children: [
if (_thermionViewer != null)
Positioned.fill(
child: ThermionWidget(
viewer: _thermionViewer!,
)),
]);
}
```

View File

@@ -0,0 +1 @@
../../thermion_dart/README.md

View File

@@ -1,96 +1,10 @@
For a more thorough example with both Flutter and pure Dart, see the [examples folder in the repository](https://github.com/nmfisher/thermion/tree/develop/examples).
# Examples
[flutter/quickstart/lib/main.dart](https://github.com/nmfisher/thermion/tree/develop/examples)
See the [Getting Started](https://thermion.dev/getting_started) and [Quickstart](https://thermion.dev/quickstart) sections of the documentation for step-by-step instructions in creating a Flutter app.
You can also jump straight to the [Quickstart example in the repository](https://github.com/nmfisher/thermion/tree/develop/examples/flutter/quickstart/lib/main.dart) for an example of a Flutter app that uses a simple 3D viewer widget.
```dart
import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion_flutter.dart';
For a more advanced example, see the [Viewer example in the repository](https://github.com/nmfisher/thermion/tree/develop/examples/flutter/viewer/lib/main.dart).
import 'package:vector_math/vector_math_64.dart' as v;
import 'dart:math';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _loaded = false;
ThermionViewer? _thermionViewer;
@override
void initState() {
super.initState();
}
Future _load() async {
var viewer = await ThermionFlutterPlugin.createViewer();
_thermionViewer = viewer;
_thermionViewer!.loadSkybox("assets/default_env_skybox.ktx");
_thermionViewer!.loadGlb("assets/cube.glb");
_thermionViewer!.setCameraPosition(0, 1, 10);
_thermionViewer!.setCameraRotation(
v.Quaternion.axisAngle(v.Vector3(1, 0, 0), -30 / 180 * pi) *
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), 15 / 180 * pi));
_thermionViewer!.addLight(LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
_thermionViewer!.setRendering(true);
_loaded = true;
setState(() {});
}
Future _unload() async {
var viewer = _thermionViewer!;
_thermionViewer = null;
setState(() {});
await viewer.dispose();
_loaded = false;
setState(() {});
}
Widget _loadButton() {
return Center(
child: ElevatedButton(child: const Text("Load"), onPressed: _load));
}
Widget _unloadButton() {
return Center(
child: ElevatedButton(child: const Text("Unload"), onPressed: _unload));
}
@override
Widget build(BuildContext context) {
return Stack(children: [
if (_thermionViewer != null)
Positioned.fill(child: ThermionWidget(viewer: _thermionViewer!)),
if (!_loaded) _loadButton(),
if (_loaded) _unloadButton(),
]);
}
}
```

View File

@@ -11,8 +11,8 @@ import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_in
class ThermionFlutterPlugin {
ThermionFlutterPlugin._();
static Future<ThermionViewer> createViewer() {
return ThermionFlutterPlatform.instance.createViewer();
static Future<ThermionViewer> createViewer({bool destroySwapchain = true}) {
return ThermionFlutterPlatform.instance.createViewer(destroySwapchain: destroySwapchain);
}
}

View File

@@ -2,8 +2,6 @@ import 'package:thermion_dart/thermion_dart.dart';
import 'package:flutter/material.dart';
import '../../../utils/camera_orientation.dart';
import 'dart:math';
class CameraOptionsWidget extends StatefulWidget {
final Camera camera;
final CameraOrientation cameraOrientation;
@@ -51,7 +49,7 @@ class _CameraOptionsWidgetState extends State<CameraOptionsWidget> {
}
Future _set() async {
await widget.camera.setCameraExposure(
await widget.camera.setExposure(
double.parse(_apertureController.text),
double.parse(_speedController.text),
double.parse(_sensitivityController.text));
@@ -59,9 +57,6 @@ class _CameraOptionsWidgetState extends State<CameraOptionsWidget> {
setState(() {});
}
double _bloom = 0.0;
double _focalLength = 26.0;
@override
Widget build(BuildContext context) {
return Theme(

View File

@@ -112,6 +112,7 @@ class _ViewerWidgetState extends State<ViewerWidget> {
});
}
@override
void didUpdateWidget(ViewerWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.manipulatorType != widget.manipulatorType) {
@@ -140,13 +141,13 @@ class _ViewerWidgetState extends State<ViewerWidget> {
viewport = thermionWidget;
case ManipulatorType.ORBIT:
viewport = ThermionListenerWidget(
key: ObjectKey(ManipulatorType.ORBIT),
key: const ObjectKey(ManipulatorType.ORBIT),
inputHandler: DelegateInputHandler.fixedOrbit(viewer!,
minimumDistance: widget.initialCameraPosition.length),
child: thermionWidget);
case ManipulatorType.FREE_FLIGHT:
viewport = ThermionListenerWidget(
key: ObjectKey(ManipulatorType.FREE_FLIGHT),
key: const ObjectKey(ManipulatorType.FREE_FLIGHT),
inputHandler: DelegateInputHandler.flight(viewer!),
child: thermionWidget);
}
@@ -178,13 +179,13 @@ class _ViewerWidgetState extends State<ViewerWidget> {
await camera.lookAt(widget.initialCameraPosition);
await viewer!.setRendering(true);
if (widget.background != null) {
await viewer!.setBackgroundColor(widget.background!.r,
widget.background!.g, widget.background!.b, widget.background!.a);
}
await viewer!.setRendering(true);
thermionWidget = ThermionWidget(
key: ObjectKey(DateTime.now()),
viewer: viewer!,

View File

@@ -1,6 +1,6 @@
name: thermion_flutter
description: Flutter plugin for 3D rendering with the Thermion toolkit.
version: 0.3.0
version: 0.3.3
homepage: https://thermion.dev
repository: https://github.com/nmfisher/thermion
@@ -17,11 +17,10 @@ dependencies:
plugin_platform_interface: ^2.0.0
ffi: ^2.1.2
animation_tools_dart: ^0.1.0
thermion_dart: ^0.3.0
thermion_flutter_platform_interface: ^0.3.0
thermion_flutter_method_channel:
path: ../thermion_flutter_method_channel
thermion_flutter_web: ^0.3.0
thermion_dart: ^0.3.3
thermion_flutter_platform_interface: ^0.3.3
thermion_flutter_method_channel: ^0.3.3
thermion_flutter_web: ^0.3.3
logging: ^1.2.0
web: ^1.0.0

View File

@@ -1,3 +1,23 @@
## 0.3.3
- Bump "thermion_flutter_method_channel" to `0.3.3`.
## 0.3.3-pre
- **FEAT**: allow passing renderTargetColorTextureFormat via ThermionFlutterOptions.
## 0.3.2
- Bump "thermion_flutter_method_channel" to `0.3.2`.
## 0.3.1
- **FIX**: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets.
## 0.3.0
- Bump "thermion_flutter_method_channel" to `0.3.0`.
## 0.3.0
> Note: This release has breaking changes.

View File

@@ -46,7 +46,7 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
return asset.buffer.asUint8List(asset.offsetInBytes);
}
Future<ThermionViewer> createViewer() async {
Future<ThermionViewer> createViewer({bool destroySwapchain = true}) async {
var driverPlatform = await channel.invokeMethod("getDriverPlatform");
var platformPtr = driverPlatform == null
@@ -118,7 +118,13 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
// TODO - see if we can use `renderStandaloneView` in FilamentViewer to
// avoid this
if (Platform.isMacOS || Platform.isIOS) {
_swapChain = await FilamentApp.instance!.createHeadlessSwapChain(1, 1, hasStencilBuffer: true);
if(destroySwapchain && _swapChain != null) {
await FilamentApp.instance!.destroySwapChain(_swapChain!);
_swapChain = null;
}
_swapChain ??= await FilamentApp.instance!
.createHeadlessSwapChain(1, 1, hasStencilBuffer: true);
await FilamentApp.instance!.register(_swapChain!, viewer.view);
await viewer.view.setRenderable(true);
}
@@ -179,10 +185,8 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
}
_swapChain = await FilamentApp.instance!.createHeadlessSwapChain(
descriptor.width,
descriptor.height,
hasStencilBuffer: true
);
descriptor.width, descriptor.height,
hasStencilBuffer: true);
_logger.info(
"Created headless swapchain ${descriptor.width}x${descriptor.height}",
@@ -208,7 +212,7 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
TextureUsage.TEXTURE_USAGE_COLOR_ATTACHMENT,
TextureUsage.TEXTURE_USAGE_SAMPLEABLE,
},
textureFormat: TextureFormat.RGBA32F,
textureFormat: options.renderTargetColorTextureFormat,
textureSamplerType: TextureSamplerType.SAMPLER_2D,
);
final depth = await FilamentApp.instance!.createTexture(
@@ -221,7 +225,7 @@ class ThermionFlutterMethodChannelPlatform extends ThermionFlutterPlatform {
TextureUsage.TEXTURE_USAGE_STENCIL_ATTACHMENT
},
textureFormat:
TextureFormat.DEPTH24_STENCIL8, // TextureFormat.DEPTH32F,
options.renderTargetDepthTextureFormat,
textureSamplerType: TextureSamplerType.SAMPLER_2D,
);

View File

@@ -1,7 +1,7 @@
name: thermion_flutter_method_channel
description: Desktop + mobile implementation for texture creation + registration with Flutter.
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
version: 0.3.0
version: 0.3.3
environment:
sdk: ">=3.3.0 <4.0.0"
@@ -23,8 +23,8 @@ dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.1.0
thermion_flutter_platform_interface: ^0.3.0
thermion_dart: ^0.3.0
thermion_flutter_platform_interface: ^0.3.3
thermion_dart: ^0.3.3
logging: ^1.2.0
dependency_overrides:
thermion_dart:

View File

@@ -1,3 +1,23 @@
## 0.3.3
- Bump "thermion_flutter_platform_interface" to `0.3.3`.
## 0.3.3-pre
- **FEAT**: allow passing renderTargetColorTextureFormat via ThermionFlutterOptions.
## 0.3.2
- Bump "thermion_flutter_platform_interface" to `0.3.2`.
## 0.3.1
- **FIX**: addDestroySwapchain argument to createViewer() (true by default). This is only used on iOS/macOS where a single swapchain is shared between all render targets.
## 0.3.0
- Bump "thermion_flutter_platform_interface" to `0.3.0`.
## 0.3.0
- **REFACTOR**: rename ThermionFlutterTexture->PlatformTextureDescriptor.

View File

@@ -7,13 +7,25 @@ import 'thermion_flutter_texture.dart';
class ThermionFlutterOptions {
final String? uberarchivePath;
final Backend? backend;
/// The format to use for the default render target color attachment.
/// Currently only applicable on iOS/macOS.
///
final TextureFormat renderTargetColorTextureFormat;
/// The format to use for the default render target depth attachment.
/// Currently only applicable on iOS/macOS.
///
final TextureFormat renderTargetDepthTextureFormat;
const ThermionFlutterOptions(
{this.uberarchivePath = null, this.backend = null});
{this.uberarchivePath = null,
this.backend = null,
this.renderTargetColorTextureFormat = TextureFormat.RGBA32F,
this.renderTargetDepthTextureFormat = TextureFormat.DEPTH24_STENCIL8});
}
class ThermionFlutterWebOptions extends ThermionFlutterOptions {
final bool createCanvas;
final bool importCanvasAsWidget;
@@ -22,8 +34,6 @@ class ThermionFlutterWebOptions extends ThermionFlutterOptions {
this.createCanvas = true,
String? uberarchivePath})
: super(uberarchivePath: uberarchivePath);
}
abstract class ThermionFlutterPlatform extends PlatformInterface {
@@ -42,15 +52,11 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
_options ??= const ThermionFlutterOptions();
return _options!;
}
///
///
///
void setOptions(covariant ThermionFlutterOptions options) {
if (_options != null) {
throw Exception(
"Options can only be set once for the entire app lifecycle.");
}
_options = options;
}
@@ -65,7 +71,7 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
///
///
///
Future<ThermionViewer> createViewer() {
Future<ThermionViewer> createViewer({bool destroySwapchain = true}) {
throw UnimplementedError();
}

View File

@@ -1,7 +1,7 @@
name: thermion_flutter_platform_interface
description: A common platform interface for the thermion_flutter plugin.
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
version: 0.3.0
version: 0.3.3
environment:
sdk: ">=3.3.0 <4.0.0"
@@ -11,7 +11,7 @@ dependencies:
flutter:
sdk: flutter
plugin_platform_interface: ^2.1.0
thermion_dart: ^0.3.0
thermion_dart: ^0.3.3
dev_dependencies:
flutter_test:

View File

@@ -1,3 +1,17 @@
## 0.3.3
- Bump "thermion_flutter_web" to `0.3.3`.
## 0.3.3-pre
- Bump "thermion_flutter_web" to `0.3.3-pre`.
## 0.3.2
- **FIX**: add missing destroySwapchain argument for web.
## 0.3.1
## 0.3.0
- **REFACTOR**: rename ThermionFlutterTexture->PlatformTextureDescriptor.

View File

@@ -40,7 +40,7 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform {
return asset.buffer.asUint8List(asset.offsetInBytes);
}
Future<ThermionViewer> createViewer() async {
Future<ThermionViewer> createViewer({bool destroySwapchain = true}) async {
HTMLCanvasElement? canvas;
if (FilamentApp.instance == null) {
// first, try and initialize bindings to see if the user has included thermion_dart.js manually in index.html
@@ -117,7 +117,7 @@ class ThermionFlutterWebPlugin extends ThermionFlutterPlatform {
///
void resizeCanvas(double width, double height) async {
_logger.info("Resizing canvas to ${width}x${height}");
Thermion_resizeCanvas((window.devicePixelRatio * width).ceil(),
resizeWebCanvas((window.devicePixelRatio * width).ceil(),
(window.devicePixelRatio * height).ceil());
}
}

View File

@@ -1,7 +1,7 @@
name: thermion_flutter_web
description: A web platform interface for the thermion_flutter plugin.
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
version: 0.3.0
version: 0.3.3
environment:
sdk: ">=3.3.0 <4.0.0"
@@ -20,10 +20,11 @@ dependencies:
sdk: flutter
plugin_platform_interface: ^2.1.0
web: ^1.0.0
thermion_dart: ^0.3.0
thermion_flutter_platform_interface: ^0.3.0
thermion_dart: ^0.3.3
thermion_flutter_platform_interface: ^0.3.3
flutter_web_plugins:
sdk: flutter
logging: ^1.3.0
dependency_overrides:
thermion_flutter_platform_interface:
path: ../thermion_flutter_platform_interface