Compare commits

..

37 Commits

Author SHA1 Message Date
Nick Fisher
a760e0e594 chore(release): publish packages
- thermion_dart@0.2.1-dev.0.0.14
 - thermion_flutter@0.2.1-dev.14
 - thermion_flutter_platform_interface@0.2.1-dev.14
 - thermion_flutter_ffi@0.2.1-dev.14
 - thermion_flutter_web@0.2.0+5
2024-10-30 11:43:21 +08:00
Nick Fisher
82bbb572a5 feat: sanitize file paths in build.dart for Windows compatibility 2024-10-30 11:43:15 +08:00
Nick Fisher
2a9158d0e0 chore: use dependency_overrides for camera_manipulation project 2024-10-30 11:43:14 +08:00
Nick Fisher
3e29749eb4 fix: reduce size of pick functor for compatibility with armeabi-v7a 2024-10-30 11:43:14 +08:00
Nick Fisher
1ac72b7c7b chore(release): publish packages
- thermion_dart@0.2.1-dev.0.0.13
 - thermion_flutter_web@0.2.0+4
 - thermion_flutter@0.2.1-dev.13
 - thermion_flutter_ffi@0.2.1-dev.13
 - thermion_flutter_platform_interface@0.2.1-dev.13
2024-10-30 11:43:14 +08:00
Nick Fisher
fb1ed9f34b chore: test cleanup 2024-10-30 11:43:14 +08:00
Nick Fisher
07bdc028df feat: pass through fragment coordinates for picking 2024-10-30 11:43:14 +08:00
Nick Fisher
4ed0e69321 chore: remove sandbox from macos quickstart project 2024-10-30 11:43:14 +08:00
Nick Fisher
61f8be2d62 test: add perspective projection test 2024-10-30 11:43:14 +08:00
Nick Fisher
25505c7648 Update dart.yml 2024-10-30 11:43:14 +08:00
Nick Fisher
7282e713ef Update dart.yml 2024-10-30 11:43:14 +08:00
Nick Fisher
d76882f194 Update dart.yml 2024-10-30 11:43:14 +08:00
Nick Fisher
d24c55033b Update dart.yml 2024-10-30 11:43:14 +08:00
Nick Fisher
64a163a6d6 chore: dummy tests 2024-10-30 11:43:14 +08:00
Nick Fisher
f4e2a4bdc6 chore: dummy tests 2024-10-30 11:43:14 +08:00
Nick Fisher
420193a7e2 chore: dummy tests 2024-10-30 11:43:14 +08:00
Nick Fisher
99b79b4f16 chore: dummy test for GitHub actions 2024-10-30 11:43:14 +08:00
Nick Fisher
d6b2e8f8d3 chore: rename test 2024-10-30 11:43:14 +08:00
Nick Fisher
014e1bfbcd Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
343f3cfd61 chore: update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
db3ec6b194 chore: update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
063a0b7ca7 chore: cleanup tests 2024-10-30 11:43:13 +08:00
Nick Fisher
5fe91f95db Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
46cfc6e72f Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
f71874cbf7 chore: remove combined integration_test 2024-10-30 11:43:13 +08:00
Nick Fisher
c793de7aba Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
ac3550a27c Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
b61e7df4ec Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
1665a9698f chore: clean up thermion_dart test directory for GitHub actions 2024-10-30 11:43:13 +08:00
Nick Fisher
53bfd894b1 chore(release): publish packages
- thermion_dart@0.2.1-dev.0.0.12
 - thermion_flutter@0.2.1-dev.12
 - thermion_flutter_web@0.2.0+3
 - thermion_flutter_platform_interface@0.2.1-dev.12
 - thermion_flutter_ffi@0.2.1-dev.12
2024-10-30 11:43:13 +08:00
Nick Fisher
f2cd165ee0 Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
8947f7c819 Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
8402619b97 Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
5c955d15db Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
e01072ff00 Update dart.yml 2024-10-30 11:43:13 +08:00
Nick Fisher
e3fe7aaa88 chore: (flutter) (example) use dependency overrides for local thermion packages. We want to build this application for CI before releasing, so we need to be testing the packages that will be built 2024-10-30 11:43:13 +08:00
Nick Fisher
ff5ac01a1d chore: (windows) remove unused libs 2024-10-30 11:43:12 +08:00
1527 changed files with 82630 additions and 275324 deletions

View File

@@ -1,29 +0,0 @@
name: 'Setup Build Environment'
description: 'Set up LLVM, MESA, and Flutter for builds'
runs:
using: 'composite'
steps:
- uses: actions/checkout@v4
- name: Setup LLVM
uses: KyleMayes/install-llvm-action@v1
with:
version: "16"
- name: Add LLVM to PATH
shell: bash
run: |
echo "${{ github.workspace }}/llvm/bin" >> $GITHUB_PATH
echo "LD_LIBRARY_PATH=${{ github.workspace }}/llvm/lib/x86_64-unknown-linux-gnu/" >> $GITHUB_ENV
- name: Verify installation
shell: bash
run: clang --version
- name: Install MESA
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y xvfb
sudo apt-get install -y libosmesa6-dev
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: master
architecture: X64

View File

@@ -1,3 +1,7 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Dart
on:
@@ -7,177 +11,96 @@ 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:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-build-env
- run: |
cd thermion_dart
dart pub get
xvfb-run dart --enable-experiment=native-assets test \
test/asset_tests.dart \
test/instancing_tests.dart \
test/light_tests.dart \
test/entity_tests.dart \
test/geometry_tests.dart \
test/view_tests.dart \
test/postprocessing_tests.dart \
test/scene_tests.dart \
test/picking_tests.dart \
--concurrency=1
#test/overlay_tests.dart \
- name: Zip output
run: zip -r output.zip ./thermion_dart/test/output
- name: Upload test output
uses: actions/upload-artifact@v4
with:
name: golden-images-${{ github.sha }}
path: output.zip
- name: Download golden images from previous run
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh run download 15990504915 \
--name golden-images-4b9870244a529bf086280331d38c55e294425b4f \
--dir ./thermion_dart/test/golden-downloads
- name: Unzip golden images
run: |
cd thermion_dart/test/golden-downloads && unzip output.zip
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
pip install Pillow numpy
- name: Compare golden images
run: cd thermion_dart/test && python compare_goldens.py
- name: Upload logs
if: failure() || steps.build.outcome == 'failure'
uses: actions/upload-artifact@v4
with:
name: build-logs
path: |
${{ github.workspace }}/thermion_dart/.dart_tool/thermion_dart/log/build.log
retention-days: 5
flutter_examples:
name: flutter_examples
runs-on: macos-latest
thermion_dart:
name: thermion_dart
runs-on: windows-2019
defaults:
run:
working-directory: examples/flutter
working-directory: thermion_dart # Adjust this path
shell: bash # This helps ensure consistent behavior across platforms
steps:
- uses: actions/checkout@v4
- name: Set up Flutter
uses: subosito/flutter-action@v2
# Enable debug logging for Actions
- name: Enable debug logging
run: echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV
# Setup Visual Studio environment
- name: Setup MSVC
uses: ilammy/msvc-dev-cmd@v1
with:
channel: master
architecture: ARM64
- name: Set up JDK 17
uses: actions/setup-java@v4
arch: x64
- uses: subosito/flutter-action@v2
with:
java-version: '17'
distribution: 'temurin'
- name: Install Android SDK
uses: android-actions/setup-android@v3
with:
api-level: 34
build-tools: 34.0.0
cmake-version: 3.22.1
ndk-version: 25.1.893739
- name: Accept Android SDK licenses
flutter-version: '3.26.0-0.1.pre' # Specify Flutter version
channel: 'master' # or 'beta', 'dev', 'master'
cache: true # Caches dependencies between runs
architecture: x64 # Explicitly specify x64 architecture
- name: Install dependencies
run: flutter pub get # even though this is a Dart package, it has as dev_dependency on objective_c for testing which for some reason has a Flutter dependency
# Ensure Visual C++ runtime is available
- name: Install Visual C++ redistributable
run: |
yes | $ANDROID_SDK_ROOT/cmdline-tools/latest/bin/sdkmanager --licenses
- run: cd quickstart && flutter pub get && flutter build macos
# - run: cd quickstart && flutter pub get && flutter build ios
- run: cd quickstart && flutter pub get && flutter build appbundle
- run: cd quickstart && flutter build web
- run: cd picking && flutter pub get && flutter build macos
# - run: cd picking && flutter pub get && flutter build ios
- run: cd picking && flutter pub get && flutter build appbundle
- run: cd picking && flutter build web
choco install visualstudio2019-workload-vctools -y
choco install vcredist140 -y
# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting
# run: dart format --output=none --set-exit-if-changed .
#- name: Analyze project source
# run: dart analyze
- name: Build and Test
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat"
dart --enable-experiment=native-assets test test/dummy_tests.dart
# Upload logs on failure
- 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
/Users/runner/work/thermion/thermion/thermion_dart/.dart_tool/thermion_dart/log/build.log
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
# Capture crash dumps if they exist
- name: Collect crash dumps
if: failure()
uses: actions/upload-artifact@v3
with:
name: crash-dumps
path: |
${{ runner.temp }}/*.dmp
${{ env.LOCALAPPDATA }}/Temp/*.dmp
${{ env.LOCALAPPDATA }}/CrashDumps/*.dmp
# thermion_dart:
# name: thermion_dart
# runs-on: macos-latest
# defaults:
# run:
# working-directory: thermion_dart
# steps:
# - uses: actions/checkout@v4
# - name: Set up Flutter
# uses: subosito/flutter-action@v2
# with:
# channel: master
# - run: flutter pub get
# - run: dart --enable-experiment=native-assets test -j1 test/light_tests.dart
# thermion_flutter:
# name: thermion_flutter
# runs-on: macos-13
# defaults:
# run:
# working-directory: thermion_flutter/thermion_flutter # Adjust this path
# steps:
# - uses: actions/checkout@v4
# - uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603
# - name: Install dependencies
# run: dart pub get
#
#
##- uses: actions/checkout@v4
#- name: Setup LLVM
# uses: KyleMayes/install-llvm-action@v1
# with:
# version: "16"
#- name: Add LLVM to PATH
# run: |
# echo "${{ github.workspace }}/llvm/bin" >> $GITHUB_PATH
# echo "LD_LIBRARY_PATH=${{ github.workspace }}/llvm/lib/x86_64-unknown-linux-gnu/" >> $GITHUB_ENV
#- name: Verify installation
# run: clang --version
#- name: Install MESA
# run: |
# sudo apt-get update
# sudo apt-get install -y xvfb
# sudo apt-get install -y libosmesa6-dev
# #sudo apt-get -y build-dep mesa
# #git clone https://gitlab.freedesktop.org/mesa/mesa.git
# #cd mesa
# #git checkout mesa-23.2.1
# #mkdir -p out
# #meson setup builddir/ -Dprefix="$(pwd)/out" -Dosmesa=true -Dglx=xlib -Dgallium-drivers=swrast -Dvulkan-drivers=swrast
# #meson install -C builddir/
#- name: Install Vulkan SDK and dependencies
# run: |
# wget -qO - https://packages.lunarg.com/lunarg-signing-key-pub.asc | sudo apt-key add -
# sudo wget -qO /etc/apt/sources.list.d/lunarg-vulkan-jammy.list https://packages.lunarg.com/vulkan/lunarg-vulkan-jammy.list
# sudo apt-get update
# sudo apt-get install -y vulkan-sdk
#- name: Set up Flutter
# uses: subosito/flutter-action@v2
# with:
# channel: master
# architecture: X64
# # Uncomment this step to verify the use of 'dart format' on each commit.
# # - name: Verify formatting
# # run: dart format --output=none --set-exit-if-changed .
# - name: Analyze project source
# run: dart analyze
# - name: Run tests
# run: dart --enable-experiment=native-assets test

2
.gitignore vendored
View File

@@ -1,4 +1,5 @@
**/*/.cxx
**/.github
**/.idea
.dart_tool
**/.dart_tool
@@ -9,4 +10,3 @@
pubspec_overrides.yaml
/pubspec.lock
*.iml
**/*/*.filamat

View File

@@ -3,305 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## 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
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.2.1-dev.20.0`](#thermion_dart---v021-dev200)
- [`thermion_flutter` - `v0.2.1-dev.20.0`](#thermion_flutter---v021-dev200)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.20.0`](#thermion_flutter_platform_interface---v021-dev200)
- [`thermion_flutter_ffi` - `v0.2.1-dev.20.0`](#thermion_flutter_ffi---v021-dev200)
- [`thermion_flutter_web` - `v0.2.0+11`](#thermion_flutter_web---v02011)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `thermion_flutter_web` - `v0.2.0+11`
---
#### `thermion_dart` - `v0.2.1-dev.20.0`
- **FIX**: only use Windows-style ndkRoot when building on Windows.
#### `thermion_flutter` - `v0.2.1-dev.20.0`
- Bump "thermion_flutter" to `0.2.1-dev.20.0`.
#### `thermion_flutter_platform_interface` - `v0.2.1-dev.20.0`
- Bump "thermion_flutter_platform_interface" to `0.2.1-dev.20.0`.
#### `thermion_flutter_ffi` - `v0.2.1-dev.20.0`
- Bump "thermion_flutter_ffi" to `0.2.1-dev.20.0`.
## 2024-11-21
### Changes
---
Packages with breaking changes:
- [`thermion_dart` - `v0.2.1-dev.19.0`](#thermion_dart---v021-dev190)
Packages with other changes:
- [`thermion_flutter` - `v0.2.1-dev.19.0`](#thermion_flutter---v021-dev190)
- [`thermion_flutter_web` - `v0.2.0+10`](#thermion_flutter_web---v02010)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.19.0`](#thermion_flutter_platform_interface---v021-dev190)
- [`thermion_flutter_ffi` - `v0.2.1-dev.19.0`](#thermion_flutter_ffi---v021-dev190)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `thermion_flutter` - `v0.2.1-dev.19.0`
- `thermion_flutter_web` - `v0.2.0+10`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.19.0`
- `thermion_flutter_ffi` - `v0.2.1-dev.19.0`
---
#### `thermion_dart` - `v0.2.1-dev.19.0`
- **FEAT**: use InputAction.ZOOM for scroll wheel in free flight handler.
- **FEAT**: free flight camera improvements.
- **BREAKING** **FIX**: update Makefile & rebuild materials for Vulkan.
## 2024-11-18
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.2.1-dev.18.0`](#thermion_dart---v021-dev180)
- [`thermion_flutter` - `v0.2.1-dev.18.0`](#thermion_flutter---v021-dev180)
- [`thermion_flutter_web` - `v0.2.0+9`](#thermion_flutter_web---v0209)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.18.0`](#thermion_flutter_platform_interface---v021-dev180)
- [`thermion_flutter_ffi` - `v0.2.1-dev.18.0`](#thermion_flutter_ffi---v021-dev180)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `thermion_flutter_web` - `v0.2.0+9`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.18.0`
- `thermion_flutter_ffi` - `v0.2.1-dev.18.0`
---
#### `thermion_dart` - `v0.2.1-dev.18.0`
- **FEAT**: add MaterialInstance.setDepthFunc.
#### `thermion_flutter` - `v0.2.1-dev.18.0`
- **FIX**: fix windows import header.
## 2024-11-15
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.2.1-dev.0.0.17`](#thermion_dart---v021-dev0017)
- [`thermion_flutter` - `v0.2.1-dev.17`](#thermion_flutter---v021-dev17)
- [`thermion_flutter_web` - `v0.2.0+8`](#thermion_flutter_web---v0208)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.17`](#thermion_flutter_platform_interface---v021-dev17)
- [`thermion_flutter_ffi` - `v0.2.1-dev.17`](#thermion_flutter_ffi---v021-dev17)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `thermion_flutter_web` - `v0.2.0+8`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.17`
- `thermion_flutter_ffi` - `v0.2.1-dev.17`
---
#### `thermion_dart` - `v0.2.1-dev.0.0.17`
- **FIX**: remove superfluous ceil() calls for picking coordinates.
- **FIX**: remove superfluous ceil() calls for picking coordinates.
- **FIX**: reduce size of pick functor for compatibility with armeabi-v7a.
- **FIX**: reduce size of pick functor for compatibility with armeabi-v7a.
- **FEAT**: add Dart methods for getRenderableBoundingBox, setParameterInt and setParameterFloat4.
- **FEAT**: Rename Gizmo material to UnlitFixedSize, and expose methods for using this material on other entities. Also exposes new methods for setting single float parameters.
- **FEAT**: expose zoomSensitivity argument for flight input handler.
- **FEAT**: Rename Gizmo material to UnlitFixedSize, and expose methods for using this material on other entities. Also exposes new methods for setting single float parameters.
- **FEAT**: expose zoomSensitivity argument for flight input handler.
- **FEAT**: sanitize file paths in build.dart for Windows compatibility.
- **FEAT**: pass through fragment coordinates for picking.
- **FEAT**: sanitize file paths in build.dart for Windows compatibility.
- **FEAT**: pass through fragment coordinates for picking.
#### `thermion_flutter` - `v0.2.1-dev.17`
- **FIX**: multiply coordinates by pixelRatio for scale events.
- **FIX**: multiply coordinates by pixelRatio for scale events.
## 2024-10-31
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.2.1-dev.0.0.16`](#thermion_dart---v021-dev0016)
- [`thermion_flutter` - `v0.2.1-dev.16`](#thermion_flutter---v021-dev16)
- [`thermion_flutter_web` - `v0.2.0+7`](#thermion_flutter_web---v0207)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.16`](#thermion_flutter_platform_interface---v021-dev16)
- [`thermion_flutter_ffi` - `v0.2.1-dev.16`](#thermion_flutter_ffi---v021-dev16)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `thermion_flutter` - `v0.2.1-dev.16`
- `thermion_flutter_web` - `v0.2.0+7`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.16`
- `thermion_flutter_ffi` - `v0.2.1-dev.16`
---
#### `thermion_dart` - `v0.2.1-dev.0.0.16`
- **FEAT**: Rename Gizmo material to UnlitFixedSize, and expose methods for using this material on other entities. Also exposes new methods for setting single float parameters.
## 2024-10-31
### Changes
---
Packages with breaking changes:
- There are no breaking changes in this release.
Packages with other changes:
- [`thermion_dart` - `v0.2.1-dev.0.0.15`](#thermion_dart---v021-dev0015)
- [`thermion_flutter` - `v0.2.1-dev.15`](#thermion_flutter---v021-dev15)
- [`thermion_flutter_web` - `v0.2.0+6`](#thermion_flutter_web---v0206)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.15`](#thermion_flutter_platform_interface---v021-dev15)
- [`thermion_flutter_ffi` - `v0.2.1-dev.15`](#thermion_flutter_ffi---v021-dev15)
Packages with dependency updates only:
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
- `thermion_flutter_web` - `v0.2.0+6`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.15`
- `thermion_flutter_ffi` - `v0.2.1-dev.15`
---
#### `thermion_dart` - `v0.2.1-dev.0.0.15`
- **FIX**: remove superfluous ceil() calls for picking coordinates.
- **FEAT**: expose zoomSensitivity argument for flight input handler.
#### `thermion_flutter` - `v0.2.1-dev.15`
- **FIX**: multiply coordinates by pixelRatio for scale events.
## 2024-10-30
### Changes

View File

@@ -1,76 +0,0 @@
FROM ubuntu:22.04
# Set non-interactive mode for apt
ENV DEBIAN_FRONTEND=noninteractive
# Install dependencies and add LLVM repository
RUN apt-get update && apt-get install -y \
git \
build-essential \
cmake \
ninja-build \
libgl1-mesa-dev \
libc++-dev \
libc++abi-dev \
libsdl2-dev \
libxi-dev \
libtbb-dev \
libassimp-dev \
python3 \
python3-pip \
curl \
wget \
software-properties-common \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
# Add LLVM repository and install Clang 16
RUN wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add - \
&& add-apt-repository "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" \
&& apt-get update \
&& apt-get install -y \
clang-16 \
clang++-16 \
libc++-16-dev \
libc++abi-16-dev \
&& rm -rf /var/lib/apt/lists/*
# Set Clang 16 as default
RUN update-alternatives --install /usr/bin/clang clang /usr/bin/clang-16 100 \
&& update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-16 100
# Set environment variables for Clang
ENV CC=clang-16
ENV CXX=clang++-16
# Set working directory
WORKDIR /opt
# Clone the filament repository
RUN git clone https://github.com/google/filament.git
# Change to filament directory
WORKDIR /opt/filament
# Checkout the specific version
RUN git checkout v1.58.0
# Add CMAKE_POSITION_INDEPENDENT_CODE setting after project() line
RUN sed -i '/^project(/a set(CMAKE_POSITION_INDEPENDENT_CODE ON)\nadd_compile_definitions(GLTFIO_USE_FILESYSTEM=0)' CMakeLists.txt
RUN sed -i -e '/^#define GLTFIO_USE_FILESYSTEM 1$/i\
#ifndef GLTFIO_USE_FILESYSTEM' -e '/^#define GLTFIO_USE_FILESYSTEM 1$/a\
#endif' libs/gltfio/src/FFilamentAsset.h
# Make build script executable
RUN chmod +x build.sh
# Run the build commands
RUN ./build.sh -l -i -f -p desktop release
RUN ./build.sh -l -i -f -p desktop release zstd
RUN ./build.sh -l -i -f -p desktop release tinyexr
RUN ./build.sh -l -i -f -p desktop release imageio
RUN zip -r filament-v1.58.0-linux-release.zip /opt/filament/out/release/filament/lib/x86_64/*.a /opt/filament/out/cmake-release/third_party/tinyexr/tnt/libtinyexr.a /opt/filament/out/cmake-release/libs/imageio/libimageio.a
# Set the working directory to the build output
WORKDIR /opt/filament/out/release
CMD ["/bin/bash"]

View File

@@ -1,59 +1,36 @@
wasm:
@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:
dart-web:
cd thermion_dart/native/web; mkdir -p build && cd build && emcmake cmake .. && emmake make
dart-web-clean:
cd thermion_dart/native/web && rm -rf build
wasm-example-web:
cd examples/dart/js_wasm
mkdir -p build
dart compile js web/example.dart -o build/example.dart.js
dart-wasm-cli-example: dart-web-clean dart-web
cd thermion_dart/examples/cli_wasm/bin && dart compile wasm example_cli.dart && node main.js
dart-web-example: dart-web
cp thermion_dart/native/web/build/build/out/thermion_dart* examples/web_wasm/bin
cd thermion_dart/examples/web_wasm/bin && dart compile wasm example_web.dart
flutter-example-web: dart-web-clean dart-web
cd thermion_flutter_federated/thermion_flutter/example/web && dart compile wasm main.dart && cd .. && flutter build web --wasm --profile
flutter-example-macos:
cd thermion_flutter_federated/thermion_flutter/example/web && flutter run -d macos
swift-bindings:
swiftc -c thermion_dart/native/macos/ThermionTexture.swift -module-name swift_module -emit-objc-header-path thermion_dart/native/include/generated/ThermionTextureSwiftObjCAPI.h -emit-library -o thermion_dart/test/generated/libThermionTextureSwift.dylib
swiftc -c thermion_flutter/thermion_flutter/macos/Classes/ThermionTexture.swift -module-name swift_module -emit-objc-header-path thermion_dart/native/include/generated/ThermionTextureSwiftObjCAPI.h -emit-library -o thermion_dart/test/libThermionTextureSwift.dylib
cd thermion_dart/ && dart --enable-experiment=native-assets run ffigen --config ffigen/swift.yaml
bindings:
cd thermion_dart/ && dart --enable-experiment=native-assets run ffigen --config ffigen/native.yaml
shared:
cd thermion_dart/native && make
# We compile a small set of custom materials for various helpers (background image, gizmo, etc)
# You must specify the `FILAMENT_PATH` environment variable, either the path /out/release
# eg: FILAMENT_PATH=/path/to/filament/out/release/bin make materials
#
materials: FORCE
ifndef FILAMENT_PATH
@echo "FILAMENT_PATH is not set"
else
@echo "Using Filament build from ${FILAMENT_PATH}"
./materials/build.sh
endif
resources: FORCE
ifndef FILAMENT_PATH
@echo "FILAMENT_PATH is not set"
else
@echo "Using Filament build from ${FILAMENT_PATH}"
@for gizmo in translation rotation; do \
$(FILAMENT_PATH)/resgen -c -p $${gizmo}_gizmo_glb -x thermion_dart/native/include/resources assets/$${gizmo}_gizmo.glb || exit 1; \
echo '#include "'$${gizmo}_gizmo_glb.h'"' | cat - thermion_dart/native/include/resources/$${gizmo}_gizmo_glb.c > thermion_dart/native/include/resources/$${gizmo}_gizmo_glb.c.new; \
mv thermion_dart/native/include/resources/$${gizmo}_gizmo_glb.c.new thermion_dart/native/include/resources/$${gizmo}_gizmo_glb.c; \
@for material in unlit image gizmo grid; do \
${FILAMENT_PATH}/matc -a opengl -a metal -o materials/$$material.filamat materials/$$material.mat; \
$(FILAMENT_PATH)/resgen -c -p $$material -x thermion_dart/native/include/material/ materials/$$material.filamat; \
echo '#include "'$$material'.h"' | cat - thermion_dart/native/include/material/$$material.c > thermion_dart/native/include/material/$$material.c.new; \
mv thermion_dart/native/include/material/$$material.c.new thermion_dart/native/include/material/$$material.c; \
done
endif
#rm materials/*.filamat
FORCE: ;

View File

@@ -3,7 +3,7 @@
<p align="center">
<a href="https://thermion.dev/quickstart">Quickstart (Flutter)</a> •
<a href="https://thermion.dev/">Documentation</a> •
<a href="https://thermion.dev/showcase">Showcase</a> •
<a href="https://thermion.dev/examples">Showcase</a> •
<a href="https://dartpad.thermion.dev/">Playground</a> •
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
</p>
@@ -15,8 +15,6 @@
<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>
https://github.com/user-attachments/assets/b0c07b5a-6156-4e42-a09b-5f9bd85fbf32
### Features
- Supports iOS (arm64), MacOS (arm64/x64), Android (arm64), Windows (x64) (>= 10), Web/WASM
@@ -24,46 +22,58 @@ https://github.com/user-attachments/assets/b0c07b5a-6156-4e42-a09b-5f9bd85fbf32
- camera/entity manipulation with mouse (desktop) and gestures (mobile)
- skinning + morph animations
Uses the Filament PBR engine (currently v1.56.4).
### Quickstart (Flutter)
From the command line:
```bash
```
flutter channel master
flutter upgrade
flutter config --enable-native-assets
```
In your Flutter app:
```
_thermionViewer = await ThermionFlutterPlugin.createViewer();
```dart
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
Positioned.fill(
child: ViewerWidget(
assetPath: "assets/cube.glb",
skyboxPath: "assets/default_env_skybox.ktx",
iblPath: "assets/default_env_ibl.ktx",
transformToUnitCube: true,
initialCameraPosition: Vector3(0, 0, 6),
background: Colors.blue,
manipulatorType: ManipulatorType.ORBIT,
onViewerAvailable: (viewer) async {
await Future.delayed(const Duration(seconds: 5));
await viewer.removeSkybox();
},
initial: Container(
color: Colors.red,
),
))]));
}
// 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);
```
> the first time you build an app that consumes this package, the Dart native-assets build system will download static binaries from Cloudflare. This may take a few minutes (depending on which platform you are compiling for). These will be cached, so subsequent builds will be much faster.
and then in your Flutter application:
```
@override
Widget build(BuildContext context) {
return Stack(children: [
if (_thermionViewer != null)
Positioned.fill(
child: ThermionWidget(
viewer: _thermionViewer!,
)),
]);
}
```
### Sponsors, Contributors & Acknowledgments
@@ -78,5 +88,4 @@ Thank you to the following people:
- @daverin for MacOS library contributions
- @LukasPoque for CI/refactoring work
- @alexmercerind for his work on integrating ANGLE textures on Flutter Windows
- @BrutalCoding for documentation fixes

Binary file not shown.

Binary file not shown.

View File

@@ -7,21 +7,15 @@
"Getting Started",
[
["Overview", "/"],
["Getting Started", "/getting_started"],
["Quick Start", "/quickstart"],
["Viewer", "/viewer"],
["Camera Manipulation", "/camera_manipulation"]
]
],
["Misc.", [
["Debugging", "/debugging"],
["Playground", "https://dartpad.thermion.dev"],
["Showcase", "/showcase"],
["Windows", "/windows"],
["Android", "/android"],
["iOS", "/ios"],
["Web", "/web"],
["Linux", "/linux"],
["Contributing", "/contributing"],
["Discord", "https://discord.gg/h2VdDK3EAQ"]
]]

View File

@@ -12,3 +12,15 @@ Thermion requires Android SDK version 22, so change your `app/android/build.grad
}
```
### Shrink/Minify Resources
In release mode, you must add the following to your `app/build.gradle`:
```
buildTypes {
release {
shrinkResources false
minifyEnabled false
}
}
```

View File

@@ -0,0 +1,63 @@
## 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.

View File

@@ -1,27 +0,0 @@
# Debugging
If something is crashing or not working as expected, you can enable verbose logging and/or debug builds (particularly useful for debugging with lldb or getting legible stack traces):
Add a `hooks` section to your app's `pubspec.yaml`, e.g.
```
name: example_cli
description: A sample command-line application.
version: 1.0.0
environment:
sdk: ^3.3.0
# Add the below
hooks:
user_defines:
thermion_dart:
mode: debug
tracing: enabled
```
After changing the `hooks` section, make sure you run `flutter clean` to propagate the changes correctly.
> [!CAUTION]
> Debug builds won't work for Android. This is a known upstream issue with Filament.
Unless `mode: debug` is specified in your `pubspec.yaml`, Thermion will use release builds under the hood, even if your app is compiled/runing in debug mode.

View File

@@ -1,40 +0,0 @@
## 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

@@ -16,7 +16,7 @@ Thermion is divided into two packages:
With this structure, the Flutter-specific components are not coupled to the Dart components, meaning Thermion can be used for rendering in both Flutter and non-Flutter applications.
For example, Thermion ships with examples for rendering with Dart only (no Flutter) with a CLI/headless application on MacOS, and with a Javascript/WASM/HTML application in browsers.
For example, Thermion ships with examples for rendering with Dart only (no Flutter) with a CLI/headless application on MacOS, and with a Javascript/WASM/HTML applicaiton in browsers.
`thermion_flutter` exports `thermion_dart`, so if you are working with a Flutter application, you will only need to import `thermion_fluttter`.

View File

@@ -1,55 +0,0 @@
## iOS
### Min iOS version
Thermion requires a minimum iOS version of 13.0. When building a Flutter application, ensure your application's `ios/Podfile` contains the following:
```ruby
platform :ios, '13.0'
```
and in ios/Info.plist:
```xml
<key>LSMinimumSystemVersion</key>
<string>13.0</string>
```
When submitting to the App Store, you may encounter an error saying `thermion_dart.framework does not supported the minimum deployment target in Info.plist`.
This is because Flutter hardcodes a deployment target of iOS 12.0 when invoking the native assets build, which conflicts with actual requirement.
After running `flutter build ios` (but before archiving the build and submitting to the App Store), run the following script to replace the `MinimumOSVersion`:
```
#!/bin/zsh
# Array of directories containing Info.plist files
directories=(
"./build/ios/iphoneos/Runner.app/Frameworks/thermion_dart.framework"
"./build/ios/Release-iphoneos/Runner.app/Frameworks/thermion_dart.framework"
"./build/native_assets/ios/thermion_dart.framework"
)
# Loop through each directory
for dir in "${directories[@]}"; do
plist_path="$dir/Info.plist"
# Check if Info.plist exists in the directory
if [[ -f "$plist_path" ]]; then
echo "Processing: $plist_path"
# Use PlistBuddy to change the MinimumOSVersion
/usr/libexec/PlistBuddy -c "Set :MinimumOSVersion 13.0" "$plist_path" 2>/dev/null
if [[ $? -eq 0 ]]; then
echo "✓ Successfully updated version to 13.0"
else
echo "✗ Failed to update version in $plist_path"
fi
else
echo "✗ Info.plist not found in $dir"
fi
done
```

View File

@@ -1,10 +0,0 @@
## Linux support
Currently, only the Dart package (`thermion_dart`) will work on Linux (primarily for the automated build/testing pipeline).
Filament has been built for Ubuntu 22.04; other distributions may work, but YMMV.
The Flutter package (`thermion_flutter`) won't work; it's missing the platform glue code necessary to set up the render target. Support will eventually be added, but there is currently no estimated timeline.
Contributions are welcome and it's actually not a lot of work. Join the Discord if you want to help out.

View File

@@ -1,197 +1,216 @@
# Quick Start
## Quickstart (Flutter)
If all you need is a quick and easy route to rendering a single 3D model in your Flutter application, start with `ViewerWidget`.
> You can find the entire project below in the [flutter/quickstart](https://github.com/nmfisher/thermion_examples/tree/master/flutter/quickstart) folder of the `thermion_examples` repository.
This is a simplified, Flutter-only wrapper around the underlying 3D rendering API with sane defaults for most people.
1. Switch to Flutter master channel, upgrade Flutter, create a new project, then add `thermion_flutter` as a dependency
`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
```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
```
## Setup
2. If running on iOS or MacOS, change the minimum deployment target to OSX 13
Follow the steps listed in [Getting Started](./getting_started) to configure your Flutter installation and project.
<Accordion title="Click to open iOS/MacOS instructions">
## Basic Usage
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
```yaml
...
flutter
uses-material-design: true
assets:
- assets/
```
3. Create an instance of `ThermionFlutterPlugin` in your app.
```dart
import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion_flutter.dart';
import 'path_to_your_viewer_widget.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ViewerWidget(
assetPath: 'assets/my_model.glb',
initialCameraPosition: Vector3(0, 0, 5),
manipulatorType: ManipulatorType.ORBIT,
),
),
);
class _MyAppState extends State<MyApp> {
  late ThermionFlutterPlugin _thermionFlutterPlugin; 
late Future<ThermionViewer> _thermionViewer;
  void initState() {   
_thermionFlutterPlugin = ThermionFlutterPlugin();   
_thermionViewer = _thermionFlutterPlugin.createViewer(); 
}
}
```
## Properties
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `initial` | `Widget` | Red decorated box | Widget to display while the viewer is loading |
| `initialCameraPosition` | `Vector3` | `Vector3(0, 0, 5)` | The starting position for the camera (looking towards origin) |
| `showFpsCounter` | `bool` | `false` | Whether to show an FPS counter overlay |
| `assetPath` | `String?` | `null` | Path to the glTF asset to load |
| `skyboxPath` | `String?` | `null` | Path to a KTX skybox image |
| `iblPath` | `String?` | `null` | Path to a KTX image for image-based lighting |
| `directLightType` | `LightType?` | `null` | Type of direct light to add to the scene |
| `transformToUnitCube` | `bool` | `true` | If true, rescales the model to fit within a 1x1x1 cube |
| `postProcessing` | `bool` | `true` | Enables ACES tone mapping and basic anti-aliasing |
| `background` | `Color?` | `null` | Background color (not visible when skybox is provided) |
| `destroyEngineOnUnload` | `bool` | `false` | If true, disposes the engine when widget is disposed |
| `manipulatorType` | `ManipulatorType` | `ORBIT` | Type of camera control to use |
| `onViewerAvailable` | `Future Function(ThermionViewer)?` | `null` | Callback when viewer is ready |
## Camera Manipulators
`ViewerWidget` supports three different camera manipulation modes:
- `ManipulatorType.NONE`: No camera controls, static view
- `ManipulatorType.ORBIT`: Orbit controls (pinch to zoom, swipe to rotate)
- `ManipulatorType.FREE_FLIGHT`: Free flight controls for unrestricted movement
Example:
4. Add a `ThermionWidget` to your widget hierarchy
```dart
ViewerWidget(
assetPath: 'assets/model.glb',
manipulatorType: ManipulatorType.FREE_FLIGHT,
)
```
## Lighting
You can set up lighting in multiple ways:
### Image-Based Lighting
```dart
ViewerWidget(
assetPath: 'assets/model.glb',
iblPath: 'assets/environment.ktx',
)
```
### Direct Light
```dart
ViewerWidget(
assetPath: 'assets/model.glb',
directLightType: LightType.SUN,
)
```
## Advanced Usage
### Accessing the Viewer
You can get access to the underlying `ThermionViewer` object for more advanced control:
```dart
ViewerWidget(
assetPath: 'assets/model.glb',
onViewerAvailable: (viewer) async {
// Now you can use the viewer directly
final camera = await viewer.getActiveCamera();
await camera.lookAt(Vector3(0, 1, 5));
class _MyAppState extends State<MyApp> {
// Add custom lights, manipulate materials, etc.
},
)
ThermionViewer? _thermionViewer;
void initState() {   
_thermionFlutterPlugin.createViewer().then((viewer) {
setState(() {
_thermionViewer = viewer;
});
});
}   
Widget build(BuildContext context) {
return Stack(children:[
if(_thermionViewer != null)
    Positioned.fill(
child:ThermionWidget(
plugin:_thermionViewer!
        ) 
    )
    ]); 
}
}
```
### Changing Manipulator at Runtime
The `manipulatorType` is the only property that can be changed after the widget is created:
4. Add a button to load the model when pressed
```dart
class _MyWidgetState extends State<MyWidget> {
ManipulatorType _manipulatorType = ManipulatorType.ORBIT;
@override
Widget build(BuildContext context) {
return Column(
children: [
Expanded(
child: ViewerWidget(
assetPath: 'assets/model.glb',
manipulatorType: _manipulatorType,
),
),
Row(
children: [
ElevatedButton(
onPressed: () {
setState(() {
_manipulatorType = ManipulatorType.ORBIT;
});
},
child: Text('Orbit'),
),
ElevatedButton(
onPressed: () {
setState(() {
_manipulatorType = ManipulatorType.FREE_FLIGHT;
});
},
child: Text('Free Flight'),
),
],
),
],
);
}
}
...
class _MyAppState extends State<MyApp> {
...
bool _loaded = false;
Widget build(BuildContext context) {
return Stack(children:[
    if(_thermionViewer != null)
    Positioned.fill(
child:ThermionWidget(
plugin:_thermionViewer!
        ) 
    ),
if (!_loaded)
Center(
child: ElevatedButton(
child: const Text("Load"),
onPressed: () async {
// TODO
_loaded = true;
setState(() {});
}))
    ]); 
}}
```
## Limitations
5. When the button is pressed, load a skybox, lighting and the glb asset
- Only the `manipulatorType` property can be changed at runtime. For any other property changes, create a new widget.
- The widget requires that you have the correct environment setup for Thermion (Flutter master channel with native assets enabled).
## Example
Here's a complete example showing how to use `ViewerWidget` with multiple configuration options:
You will need to import the `dart:math` and `package:vector_math` libraries.
```dart
import 'package:flutter/material.dart';
import 'package:thermion_flutter/thermion_flutter.dart';
import 'package:vector_math/vector_math_64.dart';
import 'package:vector_math/vector_math_64.dart' as v;
import 'dart:math';
class ModelViewer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('3D Model Viewer')),
body: ViewerWidget(
assetPath: 'assets/robot.glb',
skyboxPath: 'assets/studio_skybox.ktx',
iblPath: 'assets/studio_ibl.ktx',
initialCameraPosition: Vector3(0, 1.5, 3),
manipulatorType: ManipulatorType.ORBIT,
showFpsCounter: true,
background: Colors.grey,
postProcessing: true,
transformToUnitCube: true,
onViewerAvailable: (viewer) async {
// You can perform additional setup here
print('Viewer is ready!');
},
),
);
}
...
class _MyAppState extends State<MyApp> {
...
Widget build(BuildContext context) {
return Stack(children:[
...
if(!_loaded)
Center(
child: ElevatedButton(
child: const Text("Load"),
onPressed: () async {
var viewer = await _thermionViewer;
await viewer.loadIbl("assets/default_env_ibl.ktx");
await viewer.loadSkybox("assets/default_env_skybox.ktx");
await viewer.loadGlb("assets/cube.glb");
await viewer.setCameraPosition(0, 1, 10);
await viewer.setCameraRotation(v.Quaternion.axisAngle(
v.Vector3(1, 0, 0), -30 / 180 * pi) *
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), 15 / 180 * pi));
await viewer.addLight(
LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
await viewer.setRendering(true);
_loaded = true;
setState(() {});
}
)
)
]);
}
}
```
```
Here, we've added a skybox (the background (cube) image rendered behind all other elements in the scene), image-based lighting (where an image is used to determine the direction and intensity of a light source) and a directional light (Sun).
Anything added to the scene is referred to as an "entity" (including lights and cameras).
Entities are always added to the scene at position (0,0,0).
The default scene camera is located at (0,0,0) (and is looking at -Z, or "into" the screen), so by adding a cube at (0,0,0), the camera will now be inside the cube.
We need to move the camera outside the cube so it's visible.
6. Change the camera orientation
```dart
var viewer = await _thermionViewer;
await viewer.loadSkybox("assets/default_env_skybox.ktx");
await viewer.loadGlb("assets/cube.glb");
await viewer.setCameraPosition(0, 1, 10);
await viewer.setCameraRotation(v.Quaternion.axisAngle(
v.Vector3(1, 0, 0), -30 / 180 * pi) *
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), 15 / 180 * pi));
```
The cube still won't be visible until we add a light to the scene and tell Thermion to start rendering.
7. Add a light and turn rendering on
```dart
...
await viewer.addLight(
LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
await viewer.setRendering(true);
...
````
8. Run the project
```
$ flutter run -d macos
```
> You may experience a noticeable delay the very first time you run the project. Don't panic, it's not frozen! This is due to the build system downloading the prebuilt Filament binaries from Cloudflare, which can take some time (particularly on Windows). These binaries will be cached after first download, so subsequent runs will be much faster (though every time you run flutter clean, the binaries will be re-downloaded).
![Screenshot of Thermion Quickstart project](images/thermion_sample_project.png)
Your first Thermion project is complete!

View File

@@ -1,25 +1,18 @@
## 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)).
@@ -28,4 +21,3 @@ My personal website, where I create an interactive clone of myself with Avaturn

View File

@@ -1,186 +0,0 @@
## ThermionViewer (Flutter)
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).
If you need want more fine-grained control
> 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. Add a folder containing your assets (glTF model + skybox ktx) to your `pubspec.yaml` asset list
```yaml
...
flutter
assets:
- assets/
```
3. Create an instance of `ThermionFlutterPlugin` in your app.
```dart
class _MyAppState extends State<MyApp> {
late Future<ThermionViewer> _thermionViewer;
  void initState() {   
ThermionFlutterPlugin.createViewer().then((viewer) {
_thermionViewer = viewer;
});
}
}
```
4. Add a `ThermionWidget` to your widget hierarchy
```dart
class _MyAppState extends State<MyApp> {
ThermionViewer? _thermionViewer;
void initState() {   
_thermionFlutterPlugin.createViewer().then((viewer) {
setState(() {
_thermionViewer = viewer;
});
});
}   
Widget build(BuildContext context) {
return Stack(children:[
if(_thermionViewer != null)
    Positioned.fill(
child:ThermionWidget(
plugin:_thermionViewer!
        ) 
    )
    ]); 
}
}
```
4. Add a button to load the model when pressed
```dart
...
class _MyAppState extends State<MyApp> {
...
bool _loaded = false;
Widget build(BuildContext context) {
return Stack(children:[
    if(_thermionViewer != null)
    Positioned.fill(
child:ThermionWidget(
plugin:_thermionViewer!
        ) 
    ),
if (!_loaded)
Center(
child: ElevatedButton(
child: const Text("Load"),
onPressed: () async {
// TODO
_loaded = true;
setState(() {});
}))
    ]); 
}}
```
5. When the button is pressed, load a skybox, lighting and the glb asset
You will need to import the `dart:math` and `package:vector_math` libraries.
```dart
import 'package:vector_math/vector_math_64.dart' as v;
import 'dart:math';
...
class _MyAppState extends State<MyApp> {
...
Widget build(BuildContext context) {
return Stack(children:[
...
if(!_loaded)
Center(
child: ElevatedButton(
child: const Text("Load"),
onPressed: () async {
var viewer = await _thermionViewer;
await viewer.loadIbl("assets/default_env_ibl.ktx");
await viewer.loadSkybox("assets/default_env_skybox.ktx");
await viewer.loadGlb("assets/cube.glb");
await viewer.setCameraPosition(0, 1, 10);
await viewer.setCameraRotation(v.Quaternion.axisAngle(
v.Vector3(1, 0, 0), -30 / 180 * pi) *
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), 15 / 180 * pi));
await viewer.addLight(
LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
await viewer.setRendering(true);
_loaded = true;
setState(() {});
}
)
)
]);
}
}
```
Here, we've added a skybox (the background (cube) image rendered behind all other elements in the scene), image-based lighting (where an image is used to determine the direction and intensity of a light source) and a directional light (Sun).
Anything added to the scene is referred to as an "entity" (including lights and cameras).
Entities are always added to the scene at position (0,0,0).
The default scene camera is located at (0,0,0) (and is looking at -Z, or "into" the screen), so by adding a cube at (0,0,0), the camera will now be inside the cube.
We need to move the camera outside the cube so it's visible.
6. Change the camera orientation
```dart
var viewer = await _thermionViewer;
await viewer.loadSkybox("assets/default_env_skybox.ktx");
await viewer.loadGlb("assets/cube.glb");
await viewer.setCameraPosition(0, 1, 10);
await viewer.setCameraRotation(v.Quaternion.axisAngle(
v.Vector3(1, 0, 0), -30 / 180 * pi) *
v.Quaternion.axisAngle(v.Vector3(0, 1, 0), 15 / 180 * pi));
```
The cube still won't be visible until we add a light to the scene and tell Thermion to start rendering.
7. Add a light and turn rendering on
```dart
...
await viewer.addLight(
LightType.SUN, 7500, 50000, 0, 0, 0, 1, -1, -1);
await viewer.setRendering(true);
...
````
8. Run the project
```
$ flutter run -d macos
```
> You may experience a noticeable delay the very first time you run the project. Don't panic, it's not frozen! This is due to the build system downloading the prebuilt Filament binaries from Cloudflare, which can take some time (particularly on Windows). These binaries will be cached after first download, so subsequent runs will be much faster (though every time you run flutter clean, the binaries will be re-downloaded).
![Screenshot of Thermion Quickstart project](images/thermion_sample_project.png)
Your first Thermion project is complete!

View File

@@ -1,42 +0,0 @@
## Web
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
```
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
Copy thermion_dart.js and thermion_dart.wasm to the `/web` folder for your target app.
```
flutter run -d chrome --web-header Cross-Origin-Embedder-Policy=require-corp --web-header Cross-Origin-Opener-Policy=same-origin
```

Binary file not shown.

Binary file not shown.

View File

@@ -1,121 +0,0 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v4.2.60",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0
]
}
],
"nodes":[
{
"mesh":0,
"name":"Cube"
}
],
"materials":[
{
"doubleSided":true,
"name":"Material",
"pbrMetallicRoughness":{
"baseColorFactor":[
0.800000011920929,
0.800000011920929,
0.800000011920929,
1
],
"metallicFactor":0,
"roughnessFactor":0.5
}
}
],
"meshes":[
{
"name":"Cube",
"primitives":[
{
"attributes":{
"POSITION":0,
"NORMAL":1,
"TEXCOORD_0":2
},
"indices":3,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":24,
"max":[
1,
1,
1
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":24,
"type":"VEC3"
},
{
"bufferView":2,
"componentType":5126,
"count":24,
"type":"VEC2"
},
{
"bufferView":3,
"componentType":5123,
"count":36,
"type":"SCALAR"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":288,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":288,
"target":34962
},
{
"buffer":0,
"byteLength":192,
"byteOffset":576,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":768,
"target":34963
}
],
"buffers":[
{
"byteLength":840,
"uri":"cube.bin"
}
]
}

View File

@@ -1,183 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="200"
height="200"
viewBox="0 0 1 1"
version="1.1"
id="svg10"
sodipodi:docname="cube_texture2.svg"
inkscape:export-filename="cube_texture_512x512.png"
inkscape:export-xdpi="245.75999"
inkscape:export-ydpi="245.75999"
inkscape:version="1.4 (e7c3feb1, 2024-10-09)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10" />
<sodipodi:namedview
id="namedview10"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.5185118"
inkscape:cx="255.18405"
inkscape:cy="172.86662"
inkscape:window-width="1920"
inkscape:window-height="964"
inkscape:window-x="0"
inkscape:window-y="25"
inkscape:window-maximized="1"
inkscape:current-layer="svg10"
showgrid="false" />
<!-- Background Grid (optional, for visual aid) -->
<rect
x="0"
y="0"
width="1"
height="1"
fill="#f0f0f0"
id="rect1" />
<line
x1="0.333"
y1="0"
x2="0.333"
y2="1"
stroke="#ccc"
stroke-width="0.005"
id="line1" />
<line
x1="0.666"
y1="0"
x2="0.666"
y2="1"
stroke="#ccc"
stroke-width="0.005"
id="line2" />
<line
y1="0.25"
x1="0"
y2="0.25"
x2="1"
stroke="#ccc"
stroke-width="0.005"
id="line3" />
<line
y1="0.5"
x1="0"
y2="0.5"
x2="1"
stroke="#ccc"
stroke-width="0.005"
id="line4" />
<line
y1="0.75"
x1="0"
y2="0.75"
x2="1"
stroke="#ccc"
stroke-width="0.005"
id="line5" />
<!-- Front Face -->
<rect
x="0.333"
y="0"
width="0.333"
height="0.25"
fill="#ff0000"
id="rect5" />
<text
x="0.5"
y="0.125"
text-anchor="middle"
dominant-baseline="middle"
font-size="0.1"
fill="white"
id="text5">Front</text>
<!-- Back Face -->
<rect
x="0.333"
y="0.5"
width="0.333"
height="0.25"
fill="#00ff00"
id="rect6" />
<text
x="0.5"
y="0.625"
text-anchor="middle"
dominant-baseline="middle"
font-size="0.1"
fill="white"
id="text6">Back</text>
<!-- Top Face -->
<rect
x="0.666"
y="0.25"
width="0.333"
height="0.25"
fill="#0000ff"
id="rect7" />
<text
x="0.833"
y="0.375"
text-anchor="middle"
dominant-baseline="middle"
font-size="0.1"
fill="white"
id="text7">Top</text>
<!-- Bottom Face -->
<rect
x="0"
y="0.25"
width="0.333"
height="0.25"
fill="#ffff00"
id="rect8" />
<text
x="0.15610458"
y="0.37936932"
text-anchor="middle"
dominant-baseline="middle"
font-size="0.0733811px"
fill="#000000"
id="text8"
style="stroke-width:0.733811">Bottom</text>
<!-- Right Face -->
<rect
x="0.333"
y="0.25"
width="0.333"
height="0.25"
fill="#ff00ff"
id="rect9" />
<text
x="0.5"
y="0.375"
text-anchor="middle"
dominant-baseline="middle"
font-size="0.1"
fill="white"
id="text9">Right</text>
<!-- Left Face -->
<rect
x="0.333"
y="0.75"
width="0.333"
height="0.25"
fill="#00ffff"
id="rect10" />
<text
x="0.5"
y="0.875"
text-anchor="middle"
dominant-baseline="middle"
font-size="0.1"
fill="black"
id="text10">Left</text>
</svg>

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 313 B

View File

@@ -1,4 +0,0 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
output/**

View File

@@ -1,3 +0,0 @@
## 1.0.0
- Initial version.

View File

@@ -1,9 +0,0 @@
# cli_headless
A simple headless Dart CLI app using Thermion to render to a bitmap.
To run:
`dart --enable-experiment=native-assets run bin/example.dart`
Currently, this will probably only work on a non-virtualized macOS host.

View File

@@ -1,30 +0,0 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

View File

@@ -1,32 +0,0 @@
import 'dart:io';
import 'dart:isolate';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
void main() async {
await FFIFilamentApp.create();
final (width, height) = (500, 500);
final sc = await FilamentApp.instance!.createHeadlessSwapChain(width, height);
var viewer = ThermionViewerFFI();
await viewer.initialized;
await FilamentApp.instance!.register(sc, viewer.view);
await viewer.view.setFrustumCullingEnabled(false);
await viewer.setBackgroundColor(1, 0, 1, 1);
await viewer.setViewport(width, height);
final result = await FilamentApp.instance!.capture(
sc,
view: viewer.view,
);
final bitmap = await pixelBufferToBmp(result.first.$2, width, height,
hasAlpha: true, isFloat: true);
var outfile = File("output/render.bmp");
outfile.parent.create();
outfile.writeAsBytesSync(bitmap);
await FilamentApp.instance!.destroy();
Isolate.current.kill();
}

View File

@@ -1,21 +0,0 @@
name: example_cli
description: A sample command-line application.
version: 1.0.0
environment:
sdk: ^3.3.0
hooks:
user_defines:
thermion_dart:
mode: debug
tracing: enabled
dependencies:
thermion_dart:
path: ../../../thermion_dart
dev_dependencies:
ffigen: ^11.0.0
lints: ^3.0.0
test: ^1.24.0

View File

@@ -1,3 +0,0 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/

View File

@@ -1,3 +0,0 @@
## 1.0.0
- Initial version.

View File

@@ -1,7 +0,0 @@
# Thermion Example - Dart/Windows-only (no Flutter)
A (Windows-only) command-line application that renders into a window without Flutter.
```
dart --enable-experiment=native-assets bin\cli_windows.dart
```

View File

@@ -1,30 +0,0 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.
include: package:lints/recommended.yaml
# Uncomment the following section to specify additional rules.
# linter:
# rules:
# - camel_case_types
# analyzer:
# exclude:
# - path/to/excluded/files/**
# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints
# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options

View File

@@ -1,54 +0,0 @@
import 'dart:ffi';
import 'dart:io';
import 'dart:math';
import 'package:ffi/ffi.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart';
import 'package:cli_windows/thermion_window.g.dart';
void main(List<String> arguments) async {
var hwnd = create_thermion_window(500, 500, 0, 0);
update();
await FFIFilamentApp.create();
var viewer = ThermionViewerFFI(
loadAssetFromUri: (path) async => File(path.replaceAll("file://", "")).readAsBytesSync());
await viewer.initialized;
var swapChain = await FilamentApp.instance!.createSwapChain(Pointer<Void>.fromAddress(hwnd));
var view = viewer.view;
await view.setViewport(500, 500);
var camera = await viewer.getActiveCamera();
await camera.setLensProjection();
await FilamentApp.instance!.register(swapChain, view);
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
var skyboxPath = File("..\\..\\assets\\default_env_skybox.ktx").absolute;
await viewer.loadSkybox("file://${skyboxPath.uri.toFilePath(windows: true)}");
final cube = await viewer.createGeometry(GeometryHelper.cube());
var stopwatch = Stopwatch();
stopwatch.start();
var last = 0;
await camera.lookAt(Vector3(0, 0, 10));
while(true) {
var angle = (stopwatch.elapsedMilliseconds / 1000) * 2 * pi;
var rotation = Quaternion.axisAngle(Vector3(0,1,0), angle);
var position = Vector3(10 * sin(angle), 0, 10 * cos(angle));
var modelMatrix = Matrix4.compose(position, rotation, Vector3.all(1));
await camera.setModelMatrix(modelMatrix);
await FilamentApp.instance!.requestFrame();
update();
await Future.delayed(Duration(milliseconds: 17));
}
}

View File

@@ -1,32 +0,0 @@
import 'package:logging/logging.dart';
import 'package:native_assets_cli/native_assets_cli.dart';
import 'package:native_toolchain_c/native_toolchain_c.dart';
import 'package:path/path.dart' as path;
void main(List<String> args) async {
final logger = Logger("")
..level = Level.ALL
..onRecord.listen((record) => print(
record.message + "\n"));
await build(args, (input, output) async {
final cbuilder = CBuilder.library(
name: input.packageName,
language: Language.cpp,
assetName: 'cli_windows.dart',
sources: ['native/thermion_window.cpp'],
includes: ['native', '../../../thermion_dart/native/include'],
defines: {"UNICODE":"1"},
flags:[],
dartBuildFiles: ['hook/build.dart'],
);
await cbuilder.run(
input: input,
output: output,
logger: logger,
);
});
}

View File

@@ -1,19 +0,0 @@
// AUTO GENERATED FILE, DO NOT EDIT.
//
// Generated by `package:ffigen`.
// ignore_for_file: type=lint
@ffi.DefaultAsset('package:cli_windows/cli_windows.dart')
library;
import 'dart:ffi' as ffi;
@ffi.Native<ffi.Int Function(ffi.Int, ffi.Int, ffi.Int, ffi.Int)>(isLeaf: true)
external int create_thermion_window(
int width,
int height,
int left,
int top,
);
@ffi.Native<ffi.Void Function()>(isLeaf: true)
external void update();

View File

@@ -1,390 +0,0 @@
#pragma comment(lib, "dwmapi.lib")
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "Shlwapi.lib")
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "User32.lib")
#pragma comment(lib, "dxgi.lib")
#include <dxgi.h>
#include <cstdint>
#include <chrono>
#include <thread>
#include <algorithm>
#include <Windows.h>
#include <dwmapi.h>
#include <ShObjIdl.h>
#include <iostream>
#include <Windows.h>
#include "thermion_window.h"
namespace thermion {
void PrintDefaultGPU() {
IDXGIFactory* factory = nullptr;
CreateDXGIFactory(__uuidof(IDXGIFactory), (void**)&factory);
IDXGIAdapter* adapter = nullptr;
factory->EnumAdapters(0, &adapter); // 0 is the default adapter
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);
std::wcout << L"GPU: " << desc.Description << std::endl;
adapter->Release();
factory->Release();
}
///
/// Instantiating a ThermionWindow creates a HWND that can be passed
/// to Filament to create a swapchain.
///
///
class ThermionWindow {
public:
ThermionWindow(
int width,
int height,
int left,
int top);
HWND GetHandle();
void Resize(int width, int height, int left, int top);
uint32_t _width = 0;
uint32_t _height = 0;
uint32_t _left = 0;
uint32_t _top = 0;
private:
HWND _windowHandle;
};
static ThermionWindow* _window;
static bool _running = false;
static std::thread _renderThread;
// Add these for timing and stats
static int _frameCount = 0;
static std::chrono::time_point<std::chrono::steady_clock> _lastFpsLog;
static void RenderLoop() {
_lastFpsLog = std::chrono::steady_clock::now();
auto lastFrame = std::chrono::steady_clock::now();
while (_running) {
auto now = std::chrono::steady_clock::now();
auto frameDuration = std::chrono::duration_cast<std::chrono::microseconds>(now - lastFrame).count();
// Force a redraw
InvalidateRect(_window->GetHandle(), NULL, FALSE);
// Process any pending messages
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
_running = false;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Wait for vsync
DwmFlush();
// Update timing stats
lastFrame = now;
_frameCount++;
// Log FPS every second
auto timeSinceLastLog = std::chrono::duration_cast<std::chrono::milliseconds>(now - _lastFpsLog).count();
if (timeSinceLastLog >= 1000) { // Every second
float fps = (_frameCount * 1000.0f) / timeSinceLastLog;
float avgFrameTime = timeSinceLastLog / (float)_frameCount;
std::cout << "FPS: " << fps << " Frame Time: " << avgFrameTime << "ms"
<< " Last Frame: " << frameDuration / 1000.0f << "ms" << std::endl;
_frameCount = 0;
_lastFpsLog = now;
}
}
}
extern "C" {
EMSCRIPTEN_KEEPALIVE intptr_t create_thermion_window(int width, int height, int left, int top) {
_window = new ThermionWindow(width, height, left, top);
// Start the render thread
_running = true;
_renderThread = std::thread(RenderLoop);
return (intptr_t)_window->GetHandle();
}
// Update function can now be simplified or removed since rendering happens in the thread
EMSCRIPTEN_KEEPALIVE void update() {
}
// Add a cleanup function
EMSCRIPTEN_KEEPALIVE void cleanup() {
_running = false;
if (_renderThread.joinable()) {
_renderThread.join();
}
if (_window) {
delete _window;
_window = nullptr;
}
}
}
static constexpr auto kClassName = L"THERMION_WINDOW";
static constexpr auto kWindowName = L"thermion_window";
static bool was_window_hidden_due_to_minimize_ = false;
static WPARAM last_wm_size_wparam_ = SIZE_RESTORED;
uint64_t last_thread_time_ = 0;
static constexpr auto kNativeViewPositionAndShowDelay = 300;
typedef enum _WINDOWCOMPOSITIONATTRIB {
WCA_UNDEFINED = 0,
WCA_NCRENDERING_ENABLED = 1,
WCA_NCRENDERING_POLICY = 2,
WCA_TRANSITIONS_FORCEDISABLED = 3,
WCA_ALLOW_NCPAINT = 4,
WCA_CAPTION_BUTTON_BOUNDS = 5,
WCA_NONCLIENT_RTL_LAYOUT = 6,
WCA_FORCE_ICONIC_REPRESENTATION = 7,
WCA_EXTENDED_FRAME_BOUNDS = 8,
WCA_HAS_ICONIC_BITMAP = 9,
WCA_THEME_ATTRIBUTES = 10,
WCA_NCRENDERING_EXILED = 11,
WCA_NCADORNMENTINFO = 12,
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
WCA_VIDEO_OVERLAY_ACTIVE = 14,
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
WCA_DISALLOW_PEEK = 16,
WCA_CLOAK = 17,
WCA_CLOAKED = 18,
WCA_ACCENT_POLICY = 19,
WCA_FREEZE_REPRESENTATION = 20,
WCA_EVER_UNCLOAKED = 21,
WCA_VISUAL_OWNER = 22,
WCA_HOLOGRAPHIC = 23,
WCA_EXCLUDED_FROM_DDA = 24,
WCA_PASSIVEUPDATEMODE = 25,
WCA_USEDARKMODECOLORS = 26,
WCA_LAST = 27
} WINDOWCOMPOSITIONATTRIB;
typedef struct _WINDOWCOMPOSITIONATTRIBDATA {
WINDOWCOMPOSITIONATTRIB Attrib;
PVOID pvData;
SIZE_T cbData;
} WINDOWCOMPOSITIONATTRIBDATA;
typedef enum _ACCENT_STATE {
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
ACCENT_ENABLE_HOSTBACKDROP = 5,
ACCENT_INVALID_STATE = 6
} ACCENT_STATE;
typedef struct _ACCENT_POLICY {
ACCENT_STATE AccentState;
DWORD AccentFlags;
DWORD GradientColor;
DWORD AnimationId;
} ACCENT_POLICY;
typedef BOOL(WINAPI* _GetWindowCompositionAttribute)(
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
typedef BOOL(WINAPI* _SetWindowCompositionAttribute)(
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
static _SetWindowCompositionAttribute g_set_window_composition_attribute = NULL;
static bool g_set_window_composition_attribute_initialized = false;
typedef LONG NTSTATUS, *PNTSTATUS;
#define STATUS_SUCCESS (0x00000000)
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
RTL_OSVERSIONINFOW GetWindowsVersion() {
HMODULE hmodule = ::GetModuleHandleW(L"ntdll.dll");
if (hmodule) {
RtlGetVersionPtr rtl_get_version_ptr =
(RtlGetVersionPtr)::GetProcAddress(hmodule, "RtlGetVersion");
if (rtl_get_version_ptr != nullptr) {
RTL_OSVERSIONINFOW rovi = {0};
rovi.dwOSVersionInfoSize = sizeof(rovi);
if (STATUS_SUCCESS == rtl_get_version_ptr(&rovi)) {
return rovi;
}
}
}
RTL_OSVERSIONINFOW rovi = {0};
return rovi;
}
void SetWindowComposition(HWND window, int32_t accent_state,
int32_t gradient_color) {
// TODO: Look for a better available API.
if (GetWindowsVersion().dwBuildNumber >= 18362) {
if (!g_set_window_composition_attribute_initialized) {
auto user32 = ::GetModuleHandleA("user32.dll");
if (user32) {
g_set_window_composition_attribute =
reinterpret_cast<_SetWindowCompositionAttribute>(
::GetProcAddress(user32, "SetWindowCompositionAttribute"));
if (g_set_window_composition_attribute) {
g_set_window_composition_attribute_initialized = true;
}
}
}
ACCENT_POLICY accent = {static_cast<ACCENT_STATE>(accent_state), 2,
static_cast<DWORD>(gradient_color), 0};
WINDOWCOMPOSITIONATTRIBDATA data;
data.Attrib = WCA_ACCENT_POLICY;
data.pvData = &accent;
data.cbData = sizeof(accent);
g_set_window_composition_attribute(window, &data);
}
}
// Add tracking for drag state
static bool isDragging = false;
static POINT dragStart = {0, 0};
static POINT windowStart = {0, 0};
LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
WPARAM const wparam,
LPARAM const lparam) noexcept {
switch (message) {
case WM_DESTROY: {
PostQuitMessage(0);
return 0;
}
case WM_NCHITTEST: {
POINT pt = { LOWORD(lparam), HIWORD(lparam) };
ScreenToClient(window, &pt);
return HTCAPTION;
}
case WM_MOUSEMOVE: {
TRACKMOUSEEVENT event;
event.cbSize = sizeof(event);
event.hwndTrack = window;
event.dwFlags = TME_HOVER;
event.dwHoverTime = 200;
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
if (user_data) {
HWND flutterRootWindow = reinterpret_cast<HWND>(user_data);
LONG ex_style = ::GetWindowLong(flutterRootWindow, GWL_EXSTYLE);
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
::SetWindowLong(flutterRootWindow, GWL_EXSTYLE, ex_style);
}
break;
}
case WM_ERASEBKGND: {
HDC hdc = (HDC)wparam;
RECT rect;
GetClientRect(window, &rect);
ThermionWindow* thermionWindow = reinterpret_cast<ThermionWindow*>(
GetWindowLongPtr(window, GWLP_USERDATA));
if (thermionWindow) {
HBRUSH brush = CreateSolidBrush(RGB(0, 0, 255));
FillRect(hdc, &rect, brush);
DeleteObject(brush);
}
return TRUE;
}
case WM_SIZE:
case WM_MOVE:
case WM_MOVING:
case WM_WINDOWPOSCHANGED: {
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
if (user_data) {
HWND flutterRootWindow = reinterpret_cast<HWND>(user_data);
LONG ex_style = ::GetWindowLong(flutterRootWindow, GWL_EXSTYLE);
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
::SetWindowLong(flutterRootWindow, GWL_EXSTYLE, ex_style);
}
break;
}
default:
return ::DefWindowProc(window, message, wparam, lparam);
}
return 0;
}
ThermionWindow::ThermionWindow(int width,
int height,
int left,
int top) : _width(width), _height(height), _left(left), _top(top) {
PrintDefaultGPU();
auto window_class = WNDCLASSEX{};
::SecureZeroMemory(&window_class, sizeof(window_class));
window_class.cbSize = sizeof(window_class);
window_class.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
window_class.lpfnWndProc = FilamentWindowProc;
window_class.hInstance = GetModuleHandle(nullptr);
window_class.lpszClassName = L"THERMION_WINDOW";
window_class.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
window_class.hbrBackground = ::CreateSolidBrush(RGB(0,255,0));
::RegisterClassExW(&window_class);
// Create a normal popup window without forcing it to be topmost
_windowHandle = ::CreateWindowW(
L"THERMION_WINDOW",
L"thermion_window",
WS_OVERLAPPEDWINDOW,
left, top, width, height,
nullptr, nullptr,
GetModuleHandle(nullptr),
nullptr
);
// Store the this pointer for use in window procedure
::SetWindowLongPtr(_windowHandle, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
// Disable DWM animations
auto disable_window_transitions = TRUE;
DwmSetWindowAttribute(_windowHandle, DWMWA_TRANSITIONS_FORCEDISABLED,
&disable_window_transitions,
sizeof(disable_window_transitions));
::ShowWindow(_windowHandle, SW_SHOW);
UpdateWindow(_windowHandle);
}
void ThermionWindow::Resize(int width, int height, int left, int top) {
_width = width;
_height = height;
_left = left;
_top = top;
::SetWindowPos(_windowHandle, nullptr, left, top, width, height,
SWP_NOZORDER | SWP_NOACTIVATE);
}
HWND ThermionWindow::GetHandle() { return _windowHandle; }
} // namespace thermion

View File

@@ -1,14 +0,0 @@
#pragma once
#ifdef IS_DLL
#define EMSCRIPTEN_KEEPALIVE __declspec(dllimport)
#else
#define EMSCRIPTEN_KEEPALIVE __declspec(dllexport)
#endif
extern "C" {
intptr_t create_thermion_window(int width, int height, int left, int top);
void update();
}

View File

@@ -1,21 +0,0 @@
name: cli_windows
description: A sample command-line application with basic argument parsing.
version: 0.0.1
environment:
sdk: ^3.6.0-326.0.dev
dependencies:
args: ^2.5.0
thermion_dart:
path: ../../../thermion_dart
ffi: ^2.1.3
vector_math: ^2.1.4
native_toolchain_c: ^0.9.0
native_assets_cli: ^0.12.0
dev_dependencies:
lints: ^5.0.0
test: ^1.24.0

View File

@@ -1,19 +0,0 @@
name: example_web
description: A sample command-line application.
version: 1.0.0
# repository: https://github.com/my_org/my_repo
environment:
sdk: ^3.3.0
dependencies:
thermion_dart:
path: ../../../thermion_dart
logging: ^1.3.0
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
build_runner: ^2.4.13
build_test: ^2.2.2
build_web_compilers: ^4.1.5

View File

@@ -1 +0,0 @@
../../../assets/

View File

@@ -1,101 +0,0 @@
import 'dart:async';
import 'dart:js_interop';
import 'dart:math';
import 'package:web/web.dart';
import 'package:logging/logging.dart';
import 'package:thermion_dart/thermion_dart.dart'
hide NativeLibrary, Image_decode;
import 'package:thermion_dart/src/filament/src/implementation/ffi_filament_app.dart';
import 'web_input_handler.dart';
import 'package:thermion_dart/src/bindings/src/thermion_dart_js_interop.g.dart';
void main(List<String> arguments) async {
Logger.root.onRecord.listen((record) {
print(record);
});
NativeLibrary.initBindings("thermion_dart");
final canvas =
document.getElementById("thermion_canvas") as HTMLCanvasElement;
try {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
} catch (err) {
print(err.toString());
}
final config = FFIFilamentConfig(backend: Backend.OPENGL);
await FFIFilamentApp.create(config: config);
var swapChain = await FilamentApp.instance!
.createHeadlessSwapChain(canvas.width, canvas.height);
final viewer = ThermionViewerFFI();
await viewer.initialized;
await FilamentApp.instance!.setClearOptions(1.0, 0.0, 0.0, 1.0);
await FilamentApp.instance!.register(swapChain, viewer.view);
await viewer.setViewport(canvas.width, canvas.height);
await viewer.setRendering(true);
final rnd = Random();
// ignore: prefer_function_declarations_over_variables
bool resizing = false;
// ignore: prefer_function_declarations_over_variables
final resizer = () async {
if (resizing) {
return;
}
try {
resizing = true;
await viewer.setViewport(canvas.clientWidth, canvas.clientHeight);
Thermion_resizeCanvas(canvas.clientWidth, canvas.clientHeight);
} catch (err) {
print(err);
} finally {
resizing = false;
}
};
// ignore: unused_local_variable, prefer_function_declarations_over_variables
final jsWrapper = () {
var promise = resizer().toJS;
return promise;
};
window.addEventListener('resize', jsWrapper.toJS);
// // await FilamentApp.instance!.render();
// // await Future.delayed(Duration(seconds: 1));
// // await FilamentApp.instance!.setClearOptions(1.0, 1.0, 0.0, 1.0);
// // await FilamentApp.instance!.render();
// // await Future.delayed(Duration(seconds: 1));
await viewer.loadSkybox("assets/default_env_skybox.ktx");
await viewer.loadGltf("assets/cube.glb");
final camera = await viewer.getActiveCamera();
var zOffset = 10.0;
final inputHandler = DelegateInputHandler.flight(viewer);
final webInputHandler =
WebInputHandler(inputHandler: inputHandler, canvas: canvas);
await camera.lookAt(Vector3(0, 0, zOffset));
DateTime lastRender = DateTime.now();
while (true) {
var stackPtr = stackSave();
var now = DateTime.now();
await FilamentApp.instance!.requestFrame();
now = DateTime.now();
var timeSinceLast =
now.microsecondsSinceEpoch - lastRender.microsecondsSinceEpoch;
lastRender = now;
if (timeSinceLast < 1667) {
var waitFor = 1667 - timeSinceLast;
await Future.delayed(Duration(microseconds: waitFor));
}
stackRestore(stackPtr);
// inputHandler.keyDown(PhysicalKey.S);
// await camera.lookAt(Vector3(0,0,zOffset));
// zOffset +=0.1;
}
}

View File

@@ -1,35 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="./thermion_dart.js"></script>
<script type="module">
try {
window.thermion_dart = await thermion_dart();
} catch(err) {
console.error(err);
}
const script = document.createElement('script')
script.src = 'example.dart.js'
document.head.append(script);
</script>
<style>
html, body {
margin:0;
padding:0;
}
canvas {
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
width:100%;
height:100%;
}
</style>
</head>
<body>
<canvas id="thermion_canvas"></canvas>
</body>
</html>

View File

@@ -1,35 +0,0 @@
<html>
<head>
<script src="thermion_dart.js"></script>
<style>
html, body {
margin:0;
padding:0;
}
canvas {
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
width:100%;
height:100%;
}
</style>
</head>
<script type="module">
try {
window.thermion_dart = await thermion_dart();
} catch(err) {
console.error(err);
}
const dartModulePromise = WebAssembly.compileStreaming(fetch('./example.wasm'));
const imports = {};
const dart2wasm_runtime = await import('./example.mjs');
const moduleInstance = await dart2wasm_runtime.instantiate(dartModulePromise, imports);
await dart2wasm_runtime.invoke(moduleInstance);
</script>
<body>
<canvas id="canvas"></canvas>
</body>
</html>

View File

@@ -1,22 +0,0 @@
import { readFile } from 'fs/promises';
import { compile } from './example.mjs';
import thermion_dart from './thermion_dart.js';
async function runDartWasm() {
globalThis['thermion_dart'] = await thermion_dart();
const wasmBytes = await readFile('example.wasm');
const compiledApp = await compile(wasmBytes);
const instantiatedApp = await compiledApp.instantiate({});
try {
instantiatedApp.invokeMain();
} catch(err) {
console.error("Failed");
console.error(err);
}
}
runDartWasm().catch(console.error);

View File

@@ -1 +0,0 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.js

View File

@@ -1 +0,0 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.wasm

View File

@@ -1,299 +0,0 @@
import 'dart:js_interop';
import 'package:web/web.dart' as web;
import 'package:thermion_dart/thermion_dart.dart';
class WebInputHandler {
final InputHandler inputHandler;
final web.HTMLCanvasElement canvas;
late double pixelRatio;
final Map<int, Vector2> _touchPositions = {};
WebInputHandler({
required this.inputHandler,
required this.canvas,
}) {
pixelRatio = web.window.devicePixelRatio;
_initializeEventListeners();
}
void _initializeEventListeners() {
canvas.addEventListener('mousedown', _onMouseDown.toJS);
canvas.addEventListener('mousemove', _onMouseMove.toJS);
canvas.addEventListener('mouseup', _onMouseUp.toJS);
canvas.addEventListener('wheel', _onMouseWheel.toJS);
web.window.addEventListener('keydown', _onKeyDown.toJS);
web.window.addEventListener('keyup', _onKeyUp.toJS);
canvas.addEventListener('touchstart', _onTouchStart.toJS);
canvas.addEventListener('touchmove', _onTouchMove.toJS);
canvas.addEventListener('touchend', _onTouchEnd.toJS);
canvas.addEventListener('touchcancel', _onTouchCancel.toJS);
}
void _onMouseDown(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final button = _getMouseButtonFromEvent(event);
inputHandler.handle(MouseEvent(
MouseEventType.buttonDown,
button,
localPos,
Vector2.zero(),
));
event.preventDefault();
}
void _onMouseMove(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final delta = Vector2(event.movementX ?? 0, event.movementY ?? 0);
final button = _getMouseButtonFromEvent(event);
inputHandler.handle(MouseEvent(
MouseEventType.move,
button,
localPos,
delta,
));
event.preventDefault();
}
void _onMouseUp(web.MouseEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final button = _getMouseButtonFromEvent(event);
inputHandler.handle(MouseEvent(
MouseEventType.buttonUp,
button,
localPos,
Vector2.zero(),
));
event.preventDefault();
}
void _onMouseWheel(web.WheelEvent event) {
final localPos = _getLocalPositionFromEvent(event);
final delta = event.deltaY;
inputHandler.handle(ScrollEvent(
localPosition: localPos,
delta: delta,
));
event.preventDefault();
}
void _onKeyDown(web.KeyboardEvent event) {
PhysicalKey? physicalKey = _getPhysicalKeyFromEvent(event);
LogicalKey? logicalKey = _getLogicalKeyFromEvent(event);
if (physicalKey != null && logicalKey != null) {
inputHandler.handle(KeyEvent(KeyEventType.down, logicalKey, physicalKey));
}
event.preventDefault();
}
void _onKeyUp(web.KeyboardEvent event) {
LogicalKey? logicalKey = _getLogicalKeyFromEvent(event);
PhysicalKey? physicalKey = _getPhysicalKeyFromEvent(event);
if (physicalKey != null && logicalKey != null) {
inputHandler.handle(KeyEvent(KeyEventType.up, logicalKey, physicalKey));
}
event.preventDefault();
}
void _onTouchStart(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
final pos = _getLocalPositionFromTouch(touch);
_touchPositions[touch.identifier] = pos;
}
final touchCount = event.touches.toList().length;
if (touchCount == 1) {
final touch = event.touches.toList().first;
final pos = _getLocalPositionFromTouch(touch);
inputHandler.handle(TouchEvent(
TouchEventType.tap,
pos,
null,
));
}
if (touchCount >= 2) {
final focalPoint = _calculateFocalPoint(event.touches.toList());
inputHandler.handle(ScaleStartEvent(
numPointers: touchCount,
localFocalPoint: (focalPoint.x, focalPoint.y),
));
}
event.preventDefault();
}
void _onTouchMove(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
final id = touch.identifier;
final currPos = _getLocalPositionFromTouch(touch);
final prevPos = _touchPositions[id];
if (prevPos != null) {
_touchPositions[id] = currPos;
}
}
final touchCount = event.touches.toList().length;
if (touchCount >= 2) {
final touches = event.touches.toList();
final focalPoint = _calculateFocalPoint(touches);
// Calculate scale
final currPositions = touches.map((t) => _getLocalPositionFromTouch(t)).toList();
final prevPositions = touches.map((t) => _touchPositions[t.identifier] ?? _getLocalPositionFromTouch(t)).toList();
final currDist = (currPositions[0] - currPositions[1]).length;
final prevDist = (prevPositions[0] - prevPositions[1]).length;
final scale = prevDist > 0 ? currDist / prevDist : 1.0;
// Calculate focal point delta
final prevFocalPoint = _calculateFocalPoint(touches, prevPositions);
final focalPointDelta = focalPoint - prevFocalPoint;
inputHandler.handle(ScaleUpdateEvent(
numPointers: touchCount,
localFocalPoint: (focalPoint.x, focalPoint.y),
localFocalPointDelta: (focalPointDelta.x, focalPointDelta.y),
rotation: 0.0, // We don't track rotation in the web implementation
scale: scale,
horizontalScale: scale,
verticalScale: scale,
));
}
event.preventDefault();
}
void _onTouchEnd(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
_touchPositions.remove(touch.identifier);
}
final touchCount = event.touches.toList().length;
inputHandler.handle(ScaleEndEvent(
numPointers: touchCount,
));
event.preventDefault();
}
void _onTouchCancel(web.TouchEvent event) {
for (var touch in event.changedTouches.toList()) {
_touchPositions.remove(touch.identifier);
}
final touchCount = event.touches.toList().length;
inputHandler.handle(ScaleEndEvent(
numPointers: touchCount,
));
event.preventDefault();
}
MouseButton? _getMouseButtonFromEvent(web.MouseEvent event) {
if (event.button == 1 || (event.buttons & 4 != 0)) {
return MouseButton.middle;
} else if (event.button == 0 || (event.buttons & 1 != 0)) {
return MouseButton.left;
} else if (event.button == 2 || (event.buttons & 2 != 0)) {
return MouseButton.right;
}
return null;
}
PhysicalKey? _getPhysicalKeyFromEvent(web.KeyboardEvent event) {
switch (event.code) {
case 'KeyW':
return PhysicalKey.w;
case 'KeyA':
return PhysicalKey.a;
case 'KeyS':
return PhysicalKey.s;
case 'KeyD':
return PhysicalKey.d;
default:
return null;
}
}
LogicalKey? _getLogicalKeyFromEvent(web.KeyboardEvent event) {
switch (event.key) {
case 'KeyW':
return LogicalKey.w;
case 'KeyA':
return LogicalKey.a;
case 'KeyS':
return LogicalKey.s;
case 'KeyD':
return LogicalKey.d;
default:
return null;
}
}
Vector2 _getLocalPositionFromEvent(web.Event event) {
final rect = canvas.getBoundingClientRect();
double clientX = 0, clientY = 0;
if (event is web.MouseEvent) {
clientX = event.clientX.toDouble();
clientY = event.clientY.toDouble();
} else if (event is web.TouchEvent) {
final touch = event.touches.toList().firstOrNull;
if (touch != null) {
clientX = touch.clientX;
clientY = touch.clientY;
}
}
return Vector2(
(clientX - rect.left) * pixelRatio,
(clientY - rect.top) * pixelRatio,
);
}
Vector2 _getLocalPositionFromTouch(web.Touch touch) {
final rect = canvas.getBoundingClientRect();
return Vector2(
(touch.clientX - rect.left) * pixelRatio,
(touch.clientY - rect.top) * pixelRatio,
);
}
Vector2 _calculateFocalPoint(List<web.Touch> touches, [List<Vector2>? positions]) {
if (touches.isEmpty) return Vector2.zero();
final points = positions ?? touches.map((t) => _getLocalPositionFromTouch(t)).toList();
Vector2 sum = Vector2.zero();
for (var point in points) {
sum += point;
}
return sum.scaled(1.0 / points.length);
}
void dispose() {
canvas.removeEventListener('mousedown', _onMouseDown.toJS);
canvas.removeEventListener('mousemove', _onMouseMove.toJS);
canvas.removeEventListener('mouseup', _onMouseUp.toJS);
canvas.removeEventListener('wheel', _onMouseWheel.toJS);
web.window.removeEventListener('keydown', _onKeyDown.toJS);
web.window.removeEventListener('keyup', _onKeyUp.toJS);
canvas.removeEventListener('touchstart', _onTouchStart.toJS);
canvas.removeEventListener('touchmove', _onTouchMove.toJS);
canvas.removeEventListener('touchend', _onTouchEnd.toJS);
canvas.removeEventListener('touchcancel', _onTouchCancel.toJS);
}
}

View File

@@ -1,46 +0,0 @@
plugins {
id "com.android.application"
id "kotlin-android"
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id "dev.flutter.flutter-gradle-plugin"
}
android {
namespace = "com.example.quickstart"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_1_8
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.quickstart"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = 22
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.debug
shrinkResources false
minifyEnabled false
}
}
}
flutter {
source = "../.."
}

View File

@@ -1,48 +0,0 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="camera_manipulation"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
</manifest>

View File

@@ -1 +0,0 @@
../../assets

View File

@@ -1,167 +0,0 @@
import 'dart:async';
import 'package:logging/logging.dart';
import 'package:flutter/material.dart' hide View;
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 Animation 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 _inputHandler;
ThermionViewer? _thermionViewer;
ThermionAsset? _asset;
final _droneUri = "assets/BusterDrone/scene.gltf";
final _cubeUri = "assets/cube_with_morph_targets.glb";
String? _loaded;
final gltfAnimations = <String>[];
int selectedGltfAnimation = -1;
Future _load(String? uri) async {
if (_asset != null) {
await _thermionViewer!.destroyAsset(_asset!);
_asset = null;
}
_loaded = uri;
if (uri != null) {
_asset = await _thermionViewer!.loadGltf(uri);
await _asset!.transformToUnitCube();
final animations = await _asset!.getGltfAnimationNames();
final durations = await Future.wait(List.generate(
animations.length, (i) => _asset!.getGltfAnimationDuration(i)));
final labels = animations
.asMap()
.map((index, animation) =>
MapEntry(index, "$animation (${durations[index]}s"))
.values;
gltfAnimations.clear();
gltfAnimations.addAll(labels);
selectedGltfAnimation = 0;
}
setState(() {});
}
Future _playGltfAnimation() async {
if (selectedGltfAnimation == -1) {
throw Exception();
}
await _asset!.playGltfAnimation(selectedGltfAnimation);
}
Future _stopGltfAnimation() async {
if (selectedGltfAnimation == -1) {
throw Exception();
}
await _asset!.stopGltfAnimation(selectedGltfAnimation);
}
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
_thermionViewer = await ThermionFlutterPlugin.createViewer();
final camera = await _thermionViewer!.getActiveCamera();
await camera.lookAt(Vector3(0, 0, 10));
await _thermionViewer!.loadSkybox("assets/default_env_skybox.ktx");
await _thermionViewer!.loadIbl("assets/default_env_ibl.ktx");
await _thermionViewer!.setPostProcessing(true);
await _thermionViewer!.setRendering(true);
_inputHandler = DelegateInputHandler.fixedOrbit(_thermionViewer!);
await _load(_droneUri);
setState(() {});
});
}
@override
Widget build(BuildContext context) {
if (_thermionViewer == null) {
return Container();
}
return Stack(children: [
Positioned.fill(
child: ThermionListenerWidget(
inputHandler: _inputHandler,
child: ThermionWidget(
viewer: _thermionViewer!,
))),
Card(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Row(children: [
const Text("Asset: "),
DropdownButton<String?>(
value: _loaded,
items: [_droneUri, _cubeUri, null]
.map((uri) => DropdownMenuItem<String?>(
value: uri,
child: Text(
uri ?? "None",
style: const TextStyle(fontSize: 12),
)))
.toList(),
onChanged: _load),
const Text("Animation: "),
DropdownButton<String>(
value: selectedGltfAnimation == -1
? null
: gltfAnimations[selectedGltfAnimation],
items: gltfAnimations
.map((animation) => DropdownMenuItem<String>(
value: animation,
child: Text(
animation,
style: const TextStyle(fontSize: 12),
)))
.toList(),
onChanged: (value) {
if (value == null) {
selectedGltfAnimation = -1;
} else {
selectedGltfAnimation = gltfAnimations.indexOf(value);
}
}),
IconButton(
onPressed: _playGltfAnimation,
icon: const Icon(Icons.play_arrow)),
IconButton(
onPressed: _stopGltfAnimation, icon: const Icon(Icons.stop))
]))),
]);
}
}

View File

@@ -1,22 +0,0 @@
PODS:
- FlutterMacOS (1.0.0)
- thermion_flutter (0.0.1):
- FlutterMacOS
DEPENDENCIES:
- FlutterMacOS (from `Flutter/ephemeral`)
- thermion_flutter (from `Flutter/ephemeral/.symlinks/plugins/thermion_flutter/macos`)
EXTERNAL SOURCES:
FlutterMacOS:
:path: Flutter/ephemeral
thermion_flutter:
:path: Flutter/ephemeral/.symlinks/plugins/thermion_flutter/macos
SPEC CHECKSUMS:
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
thermion_flutter: debb51a861788780ce40e11e4400c2e5a8681fdf
PODFILE CHECKSUM: 1888651be91a8ad58692c1add9ce24279fd4e950
COCOAPODS: 1.15.2

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

View File

@@ -1,42 +0,0 @@
name: animations
description: "Thermion animation example."
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.8
vector_math: ^2.1.4
win32: 5.5.1
web: 1.0.0
thermion_flutter: ^0.2.1-dev.9
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^4.0.0
dependency_overrides:
thermion_dart:
path: ../../../thermion_dart
thermion_flutter:
path: ../../../thermion_flutter/thermion_flutter
thermion_flutter_method_channel:
path: ../../../thermion_flutter/thermion_flutter_method_channel
thermion_flutter_platform_interface:
path: ../../../thermion_flutter/thermion_flutter_platform_interface
thermion_flutter_web:
path: ../../../thermion_flutter/thermion_flutter_web
flutter:
uses-material-design: true
assets:
- assets/
- assets/BusterDrone/
- assets/BusterDrone/textures/

View File

@@ -1,59 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="quickstart">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png" />
<title>quickstart</title>
<link rel="manifest" href="manifest.json">
<script>
// The value below is injected by flutter build, do not touch.
const serviceWorkerVersion = null;
</script>
<script src="flutter.js" defer></script>
<script type="text/javascript" src="./thermion_dart.js"></script>
<script type="module">
try {
window.thermion_dart = await thermion_dart();
} catch(err) {
console.error(err);
}
</script>
</head>
<body>
<div id="flutter-container"></div>
<script type="text/javascript">
window.addEventListener('load', function (ev) {
// Download main.dart.js
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: async function (engineInitializer) {
const appRunner = await engineInitializer.initializeEngine({
hostElement: document.querySelector('#flutter-app-container')
});
await appRunner.runApp();
}
});
});
</script>
</body>
</html>

View File

@@ -1 +0,0 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.js

View File

@@ -1 +0,0 @@
../../../../thermion_dart/native/web/build/build/out/thermion_dart.wasm

View File

@@ -1,108 +0,0 @@
# Project-level configuration.
cmake_minimum_required(VERSION 3.14)
project(quickstart LANGUAGES CXX)
# The name of the executable created for the application. Change this to change
# the on-disk name of your application.
set(BINARY_NAME "quickstart")
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
# versions of CMake.
cmake_policy(VERSION 3.14...3.25)
# Define build configuration option.
get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(IS_MULTICONFIG)
set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
CACHE STRING "" FORCE)
else()
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
set(CMAKE_BUILD_TYPE "Debug" CACHE
STRING "Flutter build mode" FORCE)
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
"Debug" "Profile" "Release")
endif()
endif()
# Define settings for the Profile build mode.
set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
# Use Unicode for all projects.
add_definitions(-DUNICODE -D_UNICODE)
# Compilation settings that should be applied to most targets.
#
# Be cautious about adding new options here, as plugins use this function by
# default. In most cases, you should add new options to specific targets instead
# of modifying this function.
function(APPLY_STANDARD_SETTINGS TARGET)
target_compile_features(${TARGET} PUBLIC cxx_std_17)
target_compile_options(${TARGET} PRIVATE /W4 /wd"4100")
target_compile_options(${TARGET} PRIVATE /EHsc)
target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
target_compile_definitions(${TARGET} PRIVATE "$<$<CONFIG:Debug>:_DEBUG>")
endfunction()
# Flutter library and tool build rules.
set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
add_subdirectory(${FLUTTER_MANAGED_DIR})
# Application build; see runner/CMakeLists.txt.
add_subdirectory("runner")
# Generated plugin build rules, which manage building the plugins and adding
# them to the application.
include(flutter/generated_plugins.cmake)
# === Installation ===
# Support files are copied into place next to the executable, so that it can
# run in place. This is done instead of making a separate bundle (as on Linux)
# so that building and running from within Visual Studio will work.
set(BUILD_BUNDLE_DIR "$<TARGET_FILE_DIR:${BINARY_NAME}>")
# Make the "install" step default, as it's required to run.
set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
endif()
set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
COMPONENT Runtime)
install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
COMPONENT Runtime)
install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
if(PLUGIN_BUNDLED_LIBRARIES)
install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
endif()
# Copy the native assets provided by the build.dart from all packages.
set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/")
install(DIRECTORY "${NATIVE_ASSETS_DIR}"
DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
COMPONENT Runtime)
# Fully re-copy the assets directory on each build to avoid having stale files
# from a previous install.
set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
install(CODE "
file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
" COMPONENT Runtime)
install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
# Install the AOT library on non-Debug builds only.
install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
CONFIGURATIONS Profile;Release
COMPONENT Runtime)

View File

@@ -0,0 +1 @@
../../../assets/cube.glb

View File

@@ -0,0 +1 @@
../../../assets/default_env_ibl.ktx

View File

@@ -0,0 +1 @@
../../../assets/default_env_skybox.ktx

Some files were not shown because too many files have changed in this diff Show More