Compare commits
49 Commits
thermion_d
...
thermion_d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
071a6c8bd3 | ||
|
|
bfdda4a7cc | ||
|
|
91d653b288 | ||
|
|
54d7c4087e | ||
|
|
b88ed80ecd | ||
|
|
bbba889080 | ||
|
|
2f1c2fdd9f | ||
|
|
cee5631064 | ||
|
|
e22a0aec4d | ||
|
|
c40faeb888 | ||
|
|
f666b36e43 | ||
|
|
965be02891 | ||
|
|
a760e0e594 | ||
|
|
82bbb572a5 | ||
|
|
2a9158d0e0 | ||
|
|
3e29749eb4 | ||
|
|
1ac72b7c7b | ||
|
|
fb1ed9f34b | ||
|
|
07bdc028df | ||
|
|
4ed0e69321 | ||
|
|
61f8be2d62 | ||
|
|
25505c7648 | ||
|
|
7282e713ef | ||
|
|
d76882f194 | ||
|
|
d24c55033b | ||
|
|
64a163a6d6 | ||
|
|
f4e2a4bdc6 | ||
|
|
420193a7e2 | ||
|
|
99b79b4f16 | ||
|
|
d6b2e8f8d3 | ||
|
|
014e1bfbcd | ||
|
|
343f3cfd61 | ||
|
|
db3ec6b194 | ||
|
|
063a0b7ca7 | ||
|
|
5fe91f95db | ||
|
|
46cfc6e72f | ||
|
|
f71874cbf7 | ||
|
|
c793de7aba | ||
|
|
ac3550a27c | ||
|
|
b61e7df4ec | ||
|
|
1665a9698f | ||
|
|
53bfd894b1 | ||
|
|
f2cd165ee0 | ||
|
|
8947f7c819 | ||
|
|
8402619b97 | ||
|
|
5c955d15db | ||
|
|
e01072ff00 | ||
|
|
e3fe7aaa88 | ||
|
|
ff5ac01a1d |
60
.github/workflows/dart.yml
vendored
60
.github/workflows/dart.yml
vendored
@@ -13,30 +13,72 @@ on:
|
||||
jobs:
|
||||
thermion_dart:
|
||||
name: thermion_dart
|
||||
runs-on: macos-13
|
||||
runs-on: windows-2019
|
||||
defaults:
|
||||
run:
|
||||
working-directory: thermion_dart # Adjust this path
|
||||
shell: bash # This helps ensure consistent behavior across platforms
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
# Enable debug logging for Actions
|
||||
- name: Enable debug logging
|
||||
run: echo "ACTIONS_STEP_DEBUG=true" >> $GITHUB_ENV
|
||||
|
||||
- uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603
|
||||
# Setup Visual Studio environment
|
||||
- name: Setup MSVC
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
sdk: '3.6.0-326.0.dev'
|
||||
channel: 'dev'
|
||||
arch: x64
|
||||
- uses: subosito/flutter-action@v2
|
||||
with:
|
||||
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: dart pub get
|
||||
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: |
|
||||
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: Analyze project source
|
||||
# run: dart analyze
|
||||
|
||||
- name: Run tests
|
||||
run: dart --enable-experiment=native-assets test
|
||||
- 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
|
||||
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_flutter:
|
||||
# name: thermion_flutter
|
||||
|
||||
187
CHANGELOG.md
187
CHANGELOG.md
@@ -3,6 +3,193 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 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
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- There are no breaking changes in this release.
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.1-dev.0.0.14`](#thermion_dart---v021-dev0014)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.14`](#thermion_flutter---v021-dev14)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.14`](#thermion_flutter_platform_interface---v021-dev14)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.14`](#thermion_flutter_ffi---v021-dev14)
|
||||
- [`thermion_flutter_web` - `v0.2.0+5`](#thermion_flutter_web---v0205)
|
||||
|
||||
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.14`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.14`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.14`
|
||||
- `thermion_flutter_web` - `v0.2.0+5`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.14`
|
||||
|
||||
- **FIX**: reduce size of pick functor for compatibility with armeabi-v7a.
|
||||
- **FEAT**: sanitize file paths in build.dart for Windows compatibility.
|
||||
- **FEAT**: pass through fragment coordinates for picking.
|
||||
- **FEAT**: pass through fragment coordinates for picking.
|
||||
|
||||
|
||||
## 2024-10-29
|
||||
|
||||
### 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.13`](#thermion_dart---v021-dev0013)
|
||||
- [`thermion_flutter_web` - `v0.2.0+4`](#thermion_flutter_web---v0204)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.13`](#thermion_flutter---v021-dev13)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.13`](#thermion_flutter_ffi---v021-dev13)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.13`](#thermion_flutter_platform_interface---v021-dev13)
|
||||
|
||||
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+4`
|
||||
- `thermion_flutter` - `v0.2.1-dev.13`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.13`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.13`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.13`
|
||||
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FEAT**: pass through fragment coordinates for picking.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
|
||||
|
||||
## 2024-10-25
|
||||
|
||||
### 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.12`](#thermion_dart---v021-dev0012)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.12`](#thermion_flutter---v021-dev12)
|
||||
- [`thermion_flutter_web` - `v0.2.0+3`](#thermion_flutter_web---v0203)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.12`](#thermion_flutter_platform_interface---v021-dev12)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.12`](#thermion_flutter_ffi---v021-dev12)
|
||||
|
||||
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+3`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.12`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.12`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.12`
|
||||
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
|
||||
#### `thermion_flutter` - `v0.2.1-dev.12`
|
||||
|
||||
- **FIX**: (flutter) (windows) remove deleted source file from Windows CMakeLists.
|
||||
|
||||
|
||||
## 2024-10-25
|
||||
|
||||
### Changes
|
||||
|
||||
2
Makefile
2
Makefile
@@ -23,7 +23,7 @@ bindings:
|
||||
#
|
||||
materials: FORCE
|
||||
@echo "Using Filament build from ${FILAMENT_PATH}"
|
||||
@for material in unlit image gizmo grid; do \
|
||||
@for material in unlit image unlit_fixed_size 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; \
|
||||
|
||||
14
README.md
14
README.md
@@ -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/examples">Showcase</a> •
|
||||
<a href="https://thermion.dev/showcase">Showcase</a> •
|
||||
<a href="https://dartpad.thermion.dev/">Playground</a> •
|
||||
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
||||
</p>
|
||||
@@ -24,13 +24,17 @@
|
||||
|
||||
### Quickstart (Flutter)
|
||||
|
||||
```
|
||||
From the command line:
|
||||
|
||||
```bash
|
||||
flutter channel master
|
||||
flutter upgrade
|
||||
flutter config --enable-native-assets
|
||||
```
|
||||
|
||||
```
|
||||
In your Flutter app:
|
||||
|
||||
```dart
|
||||
_thermionViewer = await ThermionFlutterPlugin.createViewer();
|
||||
|
||||
// Geometry and models are represented as "entities". Here, we load a glTF
|
||||
@@ -61,8 +65,8 @@ await _thermionViewer!.loadIbl("assets/default_env_ibl.ktx");
|
||||
await _thermionViewer!.setRendering(true);
|
||||
```
|
||||
|
||||
and then in your Flutter application:
|
||||
```
|
||||
and then in your widget tree:
|
||||
```dart
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(children: [
|
||||
|
||||
1
examples/flutter/camera_manipulation/assets
Symbolic link
1
examples/flutter/camera_manipulation/assets
Symbolic link
@@ -0,0 +1 @@
|
||||
../../assets
|
||||
@@ -1 +0,0 @@
|
||||
../../../assets/cube.glb
|
||||
@@ -1 +0,0 @@
|
||||
../../../assets/default_env_ibl.ktx
|
||||
@@ -1 +0,0 @@
|
||||
../../../assets/default_env_skybox.ktx
|
||||
@@ -22,6 +22,16 @@ dev_dependencies:
|
||||
sdk: flutter
|
||||
flutter_lints: ^4.0.0
|
||||
|
||||
dependency_overrides:
|
||||
thermion_dart:
|
||||
path: ../../../thermion_dart
|
||||
thermion_flutter:
|
||||
path: ../../../thermion_flutter/thermion_flutter
|
||||
thermion_flutter_ffi:
|
||||
path: ../../../thermion_flutter/thermion_flutter_ffi
|
||||
thermion_flutter_platform_interface:
|
||||
path: ../../../thermion_flutter/thermion_flutter_platform_interface
|
||||
|
||||
flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
|
||||
1
examples/flutter/quickstart/assets
Symbolic link
1
examples/flutter/quickstart/assets
Symbolic link
@@ -0,0 +1 @@
|
||||
../../assets
|
||||
@@ -1 +0,0 @@
|
||||
../../../assets/cube.glb
|
||||
@@ -1 +0,0 @@
|
||||
../../../assets/default_env_ibl.ktx
|
||||
@@ -1 +0,0 @@
|
||||
../../../assets/default_env_skybox.ktx
|
||||
@@ -87,6 +87,7 @@
|
||||
93162ABED09E78126BD3CDE5 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9491FF37DFB0425E4EA0B397 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = "<group>"; };
|
||||
DB0270912CD09BDD00E05CE4 /* RunnerDebug.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RunnerDebug.entitlements; sourceTree = "<group>"; };
|
||||
E5EDF04F05E94A7EC21CBB16 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -188,6 +189,7 @@
|
||||
33FAB671232836740065AC1E /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB0270912CD09BDD00E05CE4 /* RunnerDebug.entitlements */,
|
||||
33CC10F02044A3C60003C045 /* AppDelegate.swift */,
|
||||
33CC11122044BFA00003C045 /* MainFlutterWindow.swift */,
|
||||
33E51913231747F40026EE4D /* DebugProfile.entitlements */,
|
||||
@@ -703,7 +705,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements;
|
||||
CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?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.cs.allow-jit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -16,6 +16,16 @@ dependencies:
|
||||
web: 1.0.0
|
||||
thermion_flutter: ^0.2.1-dev.7
|
||||
|
||||
dependency_overrides:
|
||||
thermion_dart:
|
||||
path: ../../../thermion_dart
|
||||
thermion_flutter:
|
||||
path: ../../../thermion_flutter/thermion_flutter
|
||||
thermion_flutter_ffi:
|
||||
path: ../../../thermion_flutter/thermion_flutter_ffi
|
||||
thermion_flutter_platform_interface:
|
||||
path: ../../../thermion_flutter/thermion_flutter_platform_interface
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
material {
|
||||
name : Gizmo,
|
||||
name : UnlitFixedSize,
|
||||
parameters : [
|
||||
{
|
||||
type : mat4,
|
||||
@@ -8,8 +8,13 @@
|
||||
},
|
||||
{
|
||||
type : float4,
|
||||
name : color,
|
||||
name : baseColorFactor,
|
||||
precision : low
|
||||
},
|
||||
{
|
||||
type: float, // the number of world-space units between the camera and the (unscaled) gizmo
|
||||
name: scale,
|
||||
precision: low
|
||||
}
|
||||
],
|
||||
depthWrite : true,
|
||||
@@ -24,14 +29,13 @@
|
||||
|
||||
vertex {
|
||||
void materialVertex(inout MaterialVertexInputs material) {
|
||||
|
||||
// we want to ensure the gizmo has the same size (in screen-space), no matter the distance from the camera
|
||||
// we do this by scaling the model-space vertex positions by the distance from the camera
|
||||
// the object should have the same size (in screen-space), no matter the distance from the camera
|
||||
// scale the model-space vertex positions by the distance from the camera
|
||||
vec4 modelSpace = getPosition();
|
||||
vec4 worldSpace = getWorldFromModelMatrix() * modelSpace;
|
||||
vec4 viewSpace = getViewFromWorldMatrix() * worldSpace;
|
||||
float distanceFromCamera = length(viewSpace.xyz);
|
||||
modelSpace.xyz *= (distanceFromCamera / 4.0f); // divide by 4 so that the size is equivalent to the camera being 4 world-space units away from the (unscaled) gizmo
|
||||
modelSpace.xyz *= (distanceFromCamera / materialParams.scale);
|
||||
|
||||
worldSpace = getWorldFromModelMatrix() * modelSpace;
|
||||
material.worldPosition = worldSpace;
|
||||
@@ -44,7 +48,7 @@
|
||||
fragment {
|
||||
void material(inout MaterialInputs material) {
|
||||
prepareMaterial(material);
|
||||
material.baseColor = materialParams.color;
|
||||
material.baseColor = materialParams.baseColorFactor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
## 0.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.
|
||||
|
||||
## 0.2.1-dev.0.0.15
|
||||
|
||||
- **FIX**: remove superfluous ceil() calls for picking coordinates.
|
||||
- **FEAT**: expose zoomSensitivity argument for flight input handler.
|
||||
|
||||
## 0.2.1-dev.0.0.14
|
||||
|
||||
- **FIX**: reduce size of pick functor for compatibility with armeabi-v7a.
|
||||
- **FEAT**: sanitize file paths in build.dart for Windows compatibility.
|
||||
- **FEAT**: pass through fragment coordinates for picking.
|
||||
- **FEAT**: pass through fragment coordinates for picking.
|
||||
|
||||
## 0.2.1-dev.0.0.13
|
||||
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FEAT**: pass through fragment coordinates for picking.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
|
||||
## 0.2.1-dev.0.0.12
|
||||
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
- **FEAT**: add SCALE2_MOVE InputType.
|
||||
|
||||
## 0.2.1-dev.0.0.12
|
||||
|
||||
- **FIX**: properly pass through loadResourcesAsync flag for loadGlbFromBuffer.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<p align="center">
|
||||
<a href="https://thermion.dev/quickstart">Quickstart (Flutter)</a> •
|
||||
<a href="https://thermion.dev/quickstart">Documentation</a> •
|
||||
<a href="https://thermion.dev/examples">Showcase</a> •
|
||||
<a href="https://thermion.dev/showcase">Showcase</a> •
|
||||
<a href="https://dartpad.thermion.dev/">Playground</a> •
|
||||
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
||||
</p>
|
||||
|
||||
@@ -3,11 +3,15 @@ import 'package:archive/archive.dart';
|
||||
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 {
|
||||
await build(args, (config, output) async {
|
||||
var logFile = File(
|
||||
"${config.packageRoot.toFilePath()}.dart_tool/thermion_dart/log/build.log");
|
||||
|
||||
var pkgRootFilePath = config.packageRoot.toFilePath(windows: Platform.isWindows);
|
||||
|
||||
var logPath = path.join(pkgRootFilePath, ".dart_tool", "thermion_dart", "log", "build.log");
|
||||
var logFile = File(logPath);
|
||||
if (!logFile.parent.existsSync()) {
|
||||
logFile.parent.createSync(recursive: true);
|
||||
}
|
||||
@@ -50,16 +54,16 @@ void main(List<String> args) async {
|
||||
|
||||
final packageName = config.packageName;
|
||||
|
||||
final sources = Directory("${config.packageRoot.toFilePath()}/native/src")
|
||||
final sources = Directory(path.join(pkgRootFilePath, "native", "src"))
|
||||
.listSync(recursive: true)
|
||||
.whereType<File>()
|
||||
.map((f) => f.path)
|
||||
.toList();
|
||||
sources.addAll([
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/gizmo_material.c",
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/image.c",
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/grid.c",
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/unlit.c",
|
||||
path.join(pkgRootFilePath, "native", "include", "material", "unlit_fixed_size.c"),
|
||||
path.join(pkgRootFilePath, "native", "include", "material", "image.c"),
|
||||
path.join(pkgRootFilePath, "native", "include", "material", "grid.c"),
|
||||
path.join(pkgRootFilePath, "native", "include", "material", "unlit.c"),
|
||||
]);
|
||||
|
||||
var libs = [
|
||||
@@ -91,9 +95,9 @@ void main(List<String> args) async {
|
||||
];
|
||||
|
||||
if (platform == "windows") {
|
||||
libDir = Directory(libDir).uri.toFilePath();
|
||||
libs = libs.map((lib) => "${libDir}${lib}.lib").toList();
|
||||
libs.addAll(["${libDir}bluevk.lib", "${libDir}bluegl.lib"]);
|
||||
libDir = Directory(libDir).uri.toFilePath(windows: config.targetOS == OS.windows);
|
||||
libs = libs.map((lib) => path.join(libDir, "${lib}.lib")).toList();
|
||||
libs.addAll([path.join(libDir,"bluevk.lib"), path.join(libDir,"bluegl.lib")]);
|
||||
libs.addAll([
|
||||
"gdi32.lib",
|
||||
"user32.lib",
|
||||
@@ -172,8 +176,8 @@ void main(List<String> args) async {
|
||||
if (platform != "windows") ...libs.map((lib) => "-l$lib"),
|
||||
if (platform != "windows") "-L$libDir",
|
||||
if (platform == "windows") ...[
|
||||
"/I${config.packageRoot.toFilePath()}\\native\\include",
|
||||
"/I${config.packageRoot.toFilePath()}native\\include\\filament",
|
||||
"/I${path.join(pkgRootFilePath, "native", "include")}",
|
||||
"/I${path.join(pkgRootFilePath, "native", "include", "filament")}",
|
||||
...sources,
|
||||
'/link',
|
||||
"/LIBPATH:$libDir",
|
||||
@@ -232,8 +236,7 @@ void main(List<String> args) async {
|
||||
name: "thermion_dart.dll",
|
||||
linkMode: DynamicLoadingBundled(),
|
||||
os: config.targetOS,
|
||||
file: Uri.file(
|
||||
config.outputDirectory.toFilePath() + "/thermion_dart.dll"),
|
||||
file: Uri.file(path.join(pkgRootFilePath, "thermion_dart.dll")),
|
||||
architecture: config.targetArchitecture),
|
||||
linkInPackage: config.packageName);
|
||||
}
|
||||
@@ -265,7 +268,7 @@ Future<Directory> getLibDir(BuildConfig config, Logger logger) async {
|
||||
}
|
||||
|
||||
var libDir = Directory(
|
||||
"${config.packageRoot.toFilePath()}/.dart_tool/thermion_dart/lib/${_FILAMENT_VERSION}/$platform/$mode/");
|
||||
path.join(config.packageRoot.toFilePath(windows:Platform.isWindows), ".dart_tool", "thermion_dart", "lib", _FILAMENT_VERSION, platform, mode));
|
||||
|
||||
if (platform == "android") {
|
||||
final archExtension = switch (config.targetArchitecture) {
|
||||
@@ -275,7 +278,7 @@ Future<Directory> getLibDir(BuildConfig config, Logger logger) async {
|
||||
Architecture.ia32 => "x86",
|
||||
_ => throw FormatException('Invalid')
|
||||
};
|
||||
libDir = Directory("${libDir.path}/$archExtension/");
|
||||
libDir = Directory(path.join(libDir.path, archExtension));
|
||||
} else if (platform == "windows") {
|
||||
if (config.targetArchitecture != Architecture.x64) {
|
||||
throw Exception(
|
||||
@@ -292,8 +295,8 @@ Future<Directory> getLibDir(BuildConfig config, Logger logger) async {
|
||||
// We will write an empty file called success to the unzip directory after successfully downloading/extracting the prebuilt libraries.
|
||||
// If this file already exists, we assume everything has been successfully extracted and skip
|
||||
final unzipDir = platform == "android" ? libDir.parent.path : libDir.path;
|
||||
final successToken = File("$unzipDir/success");
|
||||
final libraryZip = File("$unzipDir/$filename");
|
||||
final successToken = File(path.join(unzipDir, "success"));
|
||||
final libraryZip = File(path.join(unzipDir, filename));
|
||||
|
||||
if (!successToken.existsSync()) {
|
||||
if (libraryZip.existsSync()) {
|
||||
|
||||
@@ -82,6 +82,7 @@ class DelegateInputHandler implements InputHandler {
|
||||
{PickDelegate? pickDelegate,
|
||||
bool freeLook = false,
|
||||
double panSensitivity = 0.1,
|
||||
double zoomSensitivity = 0.1,
|
||||
double movementSensitivity = 0.1,
|
||||
double rotateSensitivity = 0.01,
|
||||
double? clampY,
|
||||
@@ -93,6 +94,7 @@ class DelegateInputHandler implements InputHandler {
|
||||
clampY: clampY,
|
||||
entity: entity,
|
||||
rotationSensitivity: rotateSensitivity,
|
||||
zoomSensitivity:zoomSensitivity,
|
||||
panSensitivity: panSensitivity,
|
||||
movementSensitivity: movementSensitivity),
|
||||
actions: {
|
||||
|
||||
@@ -29,7 +29,7 @@ class FFIGizmo extends BaseGizmo {
|
||||
}
|
||||
|
||||
void _onPickResult(DartEntityId entityId, int x, int y, Pointer<TView> view) {
|
||||
_callback?.call((entity: entityId, x: x, y: y));
|
||||
_callback?.call((entity: entityId, x: x, y: y, depth: 0, fragX: 0, fragY: 0, fragZ: 0));
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
@@ -150,8 +150,15 @@ external void Viewer_setViewRenderable(
|
||||
ffi.Int,
|
||||
ffi.Pointer<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(EntityId entityId, ffi.Int x, ffi.Int y,
|
||||
ffi.Pointer<TView> tView)>>)>(isLeaf: true)
|
||||
ffi.Void Function(
|
||||
EntityId entityId,
|
||||
ffi.Int x,
|
||||
ffi.Int y,
|
||||
ffi.Pointer<TView> tView,
|
||||
ffi.Float depth,
|
||||
ffi.Float fragX,
|
||||
ffi.Float fragY,
|
||||
ffi.Float fragZ)>>)>(isLeaf: true)
|
||||
external void Viewer_pick(
|
||||
ffi.Pointer<TViewer> viewer,
|
||||
ffi.Pointer<TView> tView,
|
||||
@@ -159,11 +166,24 @@ external void Viewer_pick(
|
||||
int y,
|
||||
ffi.Pointer<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(EntityId entityId, ffi.Int x, ffi.Int y,
|
||||
ffi.Pointer<TView> tView)>>
|
||||
ffi.Void Function(
|
||||
EntityId entityId,
|
||||
ffi.Int x,
|
||||
ffi.Int y,
|
||||
ffi.Pointer<TView> tView,
|
||||
ffi.Float depth,
|
||||
ffi.Float fragX,
|
||||
ffi.Float fragY,
|
||||
ffi.Float fragZ)>>
|
||||
callback,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Bool Function(ffi.Pointer<TViewer>, EntityId)>(isLeaf: true)
|
||||
external bool Viewer_isNonPickableEntity(
|
||||
ffi.Pointer<TViewer> viewer,
|
||||
int entityId,
|
||||
);
|
||||
|
||||
@ffi.Native<ffi.Pointer<TEngine> Function(ffi.Pointer<TViewer>)>(isLeaf: true)
|
||||
external ffi.Pointer<TEngine> Viewer_getEngine(
|
||||
ffi.Pointer<TViewer> viewer,
|
||||
@@ -418,23 +438,6 @@ external ffi.Pointer<TMaterialInstance> create_material_instance(
|
||||
TMaterialKey materialConfig,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TMaterialInstance> Function(
|
||||
ffi.Pointer<TSceneManager>)>(isLeaf: true)
|
||||
external ffi.Pointer<TMaterialInstance> SceneManager_createUnlitMaterialInstance(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
);
|
||||
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TMaterialInstance> Function(
|
||||
ffi.Pointer<TSceneManager>, ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterialInstance>)>>)>(isLeaf: true)
|
||||
external ffi.Pointer<TMaterialInstance> SceneManager_createUnlitMaterialInstanceRenderThread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterialInstance>)>>
|
||||
onComplete
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<TMaterialInstance>)>(isLeaf: true)
|
||||
@@ -618,6 +621,60 @@ external int get_bone(
|
||||
int boneIndex,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TGizmo> Function(ffi.Pointer<TSceneManager>, ffi.Pointer<TView>,
|
||||
ffi.Pointer<TScene>)>(isLeaf: true)
|
||||
external ffi.Pointer<TGizmo> SceneManager_createGizmo(
|
||||
ffi.Pointer<TSceneManager> tSceneManager,
|
||||
ffi.Pointer<TView> tView,
|
||||
ffi.Pointer<TScene> tScene,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
EntityId Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Uint16>,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<TMaterialInstance>,
|
||||
ffi.Bool)>(isLeaf: true)
|
||||
external int SceneManager_createGeometry(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<ffi.Float> vertices,
|
||||
int numVertices,
|
||||
ffi.Pointer<ffi.Float> normals,
|
||||
int numNormals,
|
||||
ffi.Pointer<ffi.Float> uvs,
|
||||
int numUvs,
|
||||
ffi.Pointer<ffi.Uint16> indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
ffi.Pointer<TMaterialInstance> materialInstance,
|
||||
bool keepData,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TMaterialInstance> Function(
|
||||
ffi.Pointer<TSceneManager>)>(isLeaf: true)
|
||||
external ffi.Pointer<TMaterialInstance>
|
||||
SceneManager_createUnlitMaterialInstance(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TMaterialInstance> Function(
|
||||
ffi.Pointer<TSceneManager>)>(isLeaf: true)
|
||||
external ffi.Pointer<TMaterialInstance>
|
||||
SceneManager_createUnlitFixedSizeMaterialInstance(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Bool Function(ffi.Pointer<TSceneManager>, EntityId,
|
||||
ffi.Pointer<ffi.Double>)>(isLeaf: true)
|
||||
@@ -956,35 +1013,6 @@ external void remove_animation_component(
|
||||
int entityId,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
EntityId Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Uint16>,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<TMaterialInstance>,
|
||||
ffi.Bool)>(isLeaf: true)
|
||||
external int SceneManager_createGeometry(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<ffi.Float> vertices,
|
||||
int numVertices,
|
||||
ffi.Pointer<ffi.Float> normals,
|
||||
int numNormals,
|
||||
ffi.Pointer<ffi.Float> uvs,
|
||||
int numUvs,
|
||||
ffi.Pointer<ffi.Uint16> indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
ffi.Pointer<TMaterialInstance> materialInstance,
|
||||
bool keepData,
|
||||
);
|
||||
|
||||
@ffi.Native<EntityId Function(ffi.Pointer<TSceneManager>, EntityId)>(
|
||||
isLeaf: true)
|
||||
external int get_parent(
|
||||
@@ -1195,6 +1223,15 @@ external void MaterialInstance_setParameterFloat2(
|
||||
double y,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(ffi.Pointer<TMaterialInstance>, ffi.Pointer<ffi.Char>,
|
||||
ffi.Double)>(isLeaf: true)
|
||||
external void MaterialInstance_setParameterFloat(
|
||||
ffi.Pointer<TMaterialInstance> materialInstance,
|
||||
ffi.Pointer<ffi.Char> name,
|
||||
double value,
|
||||
);
|
||||
|
||||
@ffi.Native<TViewport Function(ffi.Pointer<TView>)>(isLeaf: true)
|
||||
external TViewport View_getViewport(
|
||||
ffi.Pointer<TView> view,
|
||||
@@ -1527,6 +1564,38 @@ external void remove_skybox_render_thread(
|
||||
ffi.Pointer<TViewer> viewer,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Uint16>,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<TMaterialInstance>,
|
||||
ffi.Bool,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
|
||||
isLeaf: true)
|
||||
external void SceneManager_createGeometryRenderThread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<ffi.Float> vertices,
|
||||
int numVertices,
|
||||
ffi.Pointer<ffi.Float> normals,
|
||||
int numNormals,
|
||||
ffi.Pointer<ffi.Float> uvs,
|
||||
int numUvs,
|
||||
ffi.Pointer<ffi.Uint16> indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
ffi.Pointer<TMaterialInstance> materialInstance,
|
||||
bool keepData,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
@@ -1551,6 +1620,34 @@ external void SceneManager_loadGlbFromBufferRenderThread(
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TMaterialInstance>)>>)>(isLeaf: true)
|
||||
external void SceneManager_createUnlitMaterialInstanceRenderThread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<
|
||||
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterialInstance>)>>
|
||||
callback,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<
|
||||
ffi.NativeFunction<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TMaterialInstance>)>>)>(isLeaf: true)
|
||||
external void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<
|
||||
ffi.NativeFunction<ffi.Void Function(ffi.Pointer<TMaterialInstance>)>>
|
||||
callback,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
@@ -1751,38 +1848,6 @@ external void reset_to_rest_pose_render_thread(
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> callback,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TSceneManager>,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Float>,
|
||||
ffi.Int,
|
||||
ffi.Pointer<ffi.Uint16>,
|
||||
ffi.Int,
|
||||
ffi.Int,
|
||||
ffi.Pointer<TMaterialInstance>,
|
||||
ffi.Bool,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
|
||||
isLeaf: true)
|
||||
external void SceneManager_createGeometryRenderThread(
|
||||
ffi.Pointer<TSceneManager> sceneManager,
|
||||
ffi.Pointer<ffi.Float> vertices,
|
||||
int numVertices,
|
||||
ffi.Pointer<ffi.Float> normals,
|
||||
int numNormals,
|
||||
ffi.Pointer<ffi.Float> uvs,
|
||||
int numUvs,
|
||||
ffi.Pointer<ffi.Uint16> indices,
|
||||
int numIndices,
|
||||
int primitiveType,
|
||||
ffi.Pointer<TMaterialInstance> materialInstance,
|
||||
bool keepData,
|
||||
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(
|
||||
ffi.Pointer<TViewer>,
|
||||
@@ -2003,15 +2068,6 @@ void Camera_setProjection(
|
||||
far,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Pointer<TGizmo> Function(ffi.Pointer<TEngine>, ffi.Pointer<TView>,
|
||||
ffi.Pointer<TScene>)>(isLeaf: true)
|
||||
external ffi.Pointer<TGizmo> Gizmo_new(
|
||||
ffi.Pointer<TEngine> tEngine,
|
||||
ffi.Pointer<TView> tView,
|
||||
ffi.Pointer<TScene> tScene,
|
||||
);
|
||||
|
||||
@ffi.Native<
|
||||
ffi.Void Function(ffi.Pointer<TGizmo>, ffi.Uint32, ffi.Uint32,
|
||||
GizmoPickCallback)>(isLeaf: true)
|
||||
|
||||
@@ -84,7 +84,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
|
||||
_onPickResultCallable = NativeCallable<
|
||||
Void Function(EntityId entityId, Int x, Int y,
|
||||
Pointer<TView> view)>.listener(_onPickResult);
|
||||
Pointer<TView> view, Float depth, Float fragX, Float fragY, Float fragZ)>.listener(_onPickResult);
|
||||
|
||||
_initialize();
|
||||
}
|
||||
@@ -1509,26 +1509,26 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
|
||||
void _onPickResult(
|
||||
ThermionEntity entityId, int x, int y, Pointer<TView> viewPtr) async {
|
||||
ThermionEntity entityId, int x, int y, Pointer<TView> viewPtr, double depth, double fragX, double fragY, double fragZ) async {
|
||||
final view = FFIView(viewPtr, _viewer!);
|
||||
final viewport = await view.getViewport();
|
||||
|
||||
_pickResultController
|
||||
.add((entity: entityId, x: x.ceil(), y: (viewport.height - y).ceil()));
|
||||
.add((entity: entityId, x: x, y: (viewport.height - y), depth: depth, fragX: fragX, fragY: viewport.height - fragY, fragZ: fragZ ));
|
||||
}
|
||||
|
||||
late NativeCallable<
|
||||
Void Function(EntityId entityId, Int x, Int y, Pointer<TView> view)>
|
||||
Void Function(EntityId entityId, Int x, Int y, Pointer<TView> view, Float depth, Float fragX, Float fragY, Float fragZ)>
|
||||
_onPickResultCallable;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
void pick(int x, int y) async {
|
||||
Future pick(int x, int y) async {
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
var viewport = await view.getViewport();
|
||||
y = (viewport.height - y).ceil();
|
||||
y = viewport.height - y;
|
||||
Viewer_pick(
|
||||
_viewer!, view.view, x, y, _onPickResultCallable.nativeFunction);
|
||||
}
|
||||
@@ -2035,6 +2035,9 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
destroy_material_instance(_sceneManager!, materialInstance._pointer);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<ThermionFFIMaterialInstance> createUnlitMaterialInstance() async {
|
||||
var instance = await withPointerCallback<TMaterialInstance>((cb) {
|
||||
SceneManager_createUnlitMaterialInstanceRenderThread(_sceneManager!, cb);
|
||||
@@ -2045,6 +2048,19 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
return ThermionFFIMaterialInstance(instance);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<ThermionFFIMaterialInstance> createUnlitFixedSizeMaterialInstance() async {
|
||||
var instance = await withPointerCallback<TMaterialInstance>((cb) {
|
||||
SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(_sceneManager!, cb);
|
||||
});
|
||||
if (instance == nullptr) {
|
||||
throw Exception("Failed to create material instance");
|
||||
}
|
||||
return ThermionFFIMaterialInstance(instance);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyInt(ThermionEntity entity, String propertyName,
|
||||
int materialIndex, int value) {
|
||||
@@ -2163,7 +2179,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
Future<Gizmo> createGizmo(FFIView view) async {
|
||||
var view = (await getViewAt(0)) as FFIView;
|
||||
var scene = View_getScene(view.view);
|
||||
final gizmo = Gizmo_new(Viewer_getEngine(_viewer!), view.view, scene);
|
||||
final gizmo = SceneManager_createGizmo(_sceneManager!, view.view, scene);
|
||||
return FFIGizmo(gizmo, this);
|
||||
}
|
||||
}
|
||||
@@ -2194,6 +2210,12 @@ class ThermionFFIMaterialInstance extends MaterialInstance {
|
||||
MaterialInstance_setParameterFloat2(
|
||||
_pointer, name.toNativeUtf8().cast<Char>(), x, y);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParameterFloat(String name, double value) async {
|
||||
MaterialInstance_setParameterFloat(
|
||||
_pointer, name.toNativeUtf8().cast<Char>(), value);
|
||||
}
|
||||
}
|
||||
|
||||
class FFIRenderTarget extends RenderTarget {
|
||||
|
||||
@@ -2,6 +2,7 @@ abstract class MaterialInstance {
|
||||
Future setDepthWriteEnabled(bool enabled);
|
||||
Future setDepthCullingEnabled(bool enabled);
|
||||
Future setParameterFloat2(String name, double x, double y);
|
||||
Future setParameterFloat(String name, double x);
|
||||
}
|
||||
|
||||
enum AlphaMode { OPAQUE, MASK, BLEND }
|
||||
|
||||
@@ -1,5 +1,17 @@
|
||||
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
|
||||
import '../../viewer.dart';
|
||||
|
||||
typedef FilamentPickResult = ({ThermionEntity entity, int x, int y});
|
||||
/// The result of a picking operation (see [ThermionViewer.pick] for more details).
|
||||
/// [x] and [y] refer to the original screen coordinates used to call [pick]; this should
|
||||
/// match the values of [fragX] and [fragY]. [fragZ] is the depth value in screen coordinates,
|
||||
/// [depth] is the value in the depth buffer (i.e. fragZ = 1.0 - depth).
|
||||
///
|
||||
typedef FilamentPickResult = ({
|
||||
ThermionEntity entity,
|
||||
int x,
|
||||
int y,
|
||||
double depth,
|
||||
double fragX,
|
||||
double fragY,
|
||||
double fragZ
|
||||
});
|
||||
typedef PickResult = FilamentPickResult;
|
||||
|
||||
@@ -695,7 +695,7 @@ abstract class ThermionViewer {
|
||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [pickResult] stream to receive the results of this method.
|
||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||
///
|
||||
void pick(int x, int y);
|
||||
Future pick(int x, int y);
|
||||
|
||||
///
|
||||
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
|
||||
@@ -895,6 +895,11 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future<MaterialInstance> createUnlitMaterialInstance();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<MaterialInstance> createUnlitFixedSizeMaterialInstance();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
|
||||
@@ -21,4 +21,10 @@ class ThermionWasmMaterialInstance extends MaterialInstance {
|
||||
// TODO: implement setParameterFloat2
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParameterFloat(String name, double x) {
|
||||
// TODO: implement setParameterFloat
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +98,15 @@ namespace thermion
|
||||
void clearBackgroundImage();
|
||||
void setBackgroundImagePosition(float x, float y, bool clamp, uint32_t width, uint32_t height);
|
||||
|
||||
void pick(View *view, uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y, View *view));
|
||||
typedef void (*PickCallback)(EntityId entityId, int x, int y, View *view, float depth, float fragX, float fragY, float fragZ);
|
||||
|
||||
///
|
||||
/// Returns true if the specified entity is a gizmo, grid or background image entity.
|
||||
///
|
||||
bool isNonPickableEntity(EntityId entityId);
|
||||
|
||||
void pick(View *view, uint32_t x, uint32_t y, PickCallback callback);
|
||||
|
||||
Engine* getEngine() {
|
||||
return _engine;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/InstanceBuffer.h>
|
||||
|
||||
#include "material/gizmo.h"
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
namespace thermion {
|
||||
@@ -31,7 +29,7 @@ class Gizmo {
|
||||
enum Axis { X, Y, Z};
|
||||
|
||||
public:
|
||||
Gizmo(Engine *engine, View *view, Scene *scene);
|
||||
Gizmo(Engine *engine, View *view, Scene *scene, Material* material);
|
||||
~Gizmo();
|
||||
|
||||
typedef void (*PickCallback)(EntityId entityId, uint32_t x, uint32_t y, View *view);
|
||||
@@ -91,8 +89,10 @@ class Gizmo {
|
||||
Engine *_engine;
|
||||
Scene *_scene;
|
||||
View *_view;
|
||||
utils::Entity _entities[7] = { utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity() };
|
||||
Material* _material;
|
||||
|
||||
utils::Entity _entities[7] = { utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity() };
|
||||
|
||||
MaterialInstance* _materialInstances[7];
|
||||
math::float4 inactiveColors[3] {
|
||||
math::float4 { 1.0f, 0.0f, 0.0f, 0.5f },
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/InstanceBuffer.h>
|
||||
|
||||
#include "material/gizmo.h"
|
||||
|
||||
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -19,16 +19,17 @@
|
||||
#include <filament/InstanceBuffer.h>
|
||||
#include <utils/NameComponentManager.h>
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "tsl/robin_map.h"
|
||||
|
||||
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "Gizmo.hpp"
|
||||
#include "GridOverlay.hpp"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "components/CollisionComponentManager.hpp"
|
||||
#include "components/AnimationComponentManager.hpp"
|
||||
|
||||
#include "tsl/robin_map.h"
|
||||
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
@@ -287,6 +288,8 @@ namespace thermion
|
||||
return _ubershaderProvider;
|
||||
}
|
||||
|
||||
MaterialInstance* createUnlitFixedSizeMaterialInstance();
|
||||
|
||||
MaterialInstance* createUnlitMaterialInstance();
|
||||
|
||||
void setVisibilityLayer(EntityId entityId, int layer);
|
||||
@@ -299,6 +302,8 @@ namespace thermion
|
||||
|
||||
Camera* getCameraAt(size_t index);
|
||||
|
||||
Gizmo *createGizmo(View *view, Scene *scene);
|
||||
|
||||
bool isGizmoEntity(utils::Entity entity);
|
||||
|
||||
Scene* getScene() {
|
||||
@@ -321,6 +326,8 @@ namespace thermion
|
||||
std::mutex _stencilMutex;
|
||||
std::vector<MaterialInstance*> _materialInstances;
|
||||
|
||||
Material* _gizmoMaterial = nullptr;
|
||||
|
||||
utils::NameComponentManager *_ncm;
|
||||
|
||||
tsl::robin_map<
|
||||
|
||||
@@ -10,7 +10,6 @@ extern "C"
|
||||
|
||||
typedef void (*GizmoPickCallback)(EntityId entityId, uint32_t x, uint32_t y, TView* view);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TGizmo* Gizmo_new(TEngine *tEngine, TView *tView, TScene *tScene);
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback);
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_setVisibility(TGizmo *tGizmo, bool visible);
|
||||
|
||||
|
||||
@@ -85,7 +85,8 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *viewer, TSwapChain *swapChain, TView* view, bool renderable);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *viewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *viewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView, float depth, float fragX, float fragY, float fragZ));
|
||||
EMSCRIPTEN_KEEPALIVE bool Viewer_isNonPickableEntity(TViewer *viewer, EntityId entityId);
|
||||
|
||||
// Engine
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
|
||||
@@ -197,6 +198,7 @@ extern "C"
|
||||
int skinIndex,
|
||||
int boneIndex);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TGizmo* SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_createGeometry(
|
||||
TSceneManager *sceneManager,
|
||||
float *vertices,
|
||||
@@ -211,6 +213,7 @@ extern "C"
|
||||
TMaterialInstance *materialInstance,
|
||||
bool keepData);
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitMaterialInstance(TSceneManager *sceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE bool SceneManager_setTransform(TSceneManager *sceneManager, EntityId entityId, const double *const transform);
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *sceneManager, EntityId* entities, const double* const transforms, int numEntities);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_findCameraByName(TSceneManager* tSceneManager, EntityId entity, const char* name);
|
||||
@@ -294,6 +297,7 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* materialInstance, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance* materialInstance, const char* name, double x, double y);
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance* materialInstance, const char* name, double value);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@@ -67,6 +67,7 @@ extern "C"
|
||||
void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*));
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*));
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void create_instance_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)(EntityId));
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#pragma comment(lib, "bluevk.lib")
|
||||
#pragma comment(lib, "bluegl.lib")
|
||||
#pragma comment(lib, "backend.lib")
|
||||
#pragma comment(lib, "filameshio.lib")
|
||||
#pragma comment(lib, "viewer.lib")
|
||||
#pragma comment(lib, "filamat.lib")
|
||||
#pragma comment(lib, "geometry.lib")
|
||||
#pragma comment(lib, "utils.lib")
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
.global GIZMO_GIZMO_OFFSET;
|
||||
.global GIZMO_GIZMO_SIZE;
|
||||
|
||||
.global GIZMO_PACKAGE
|
||||
.section .rodata
|
||||
GIZMO_PACKAGE:
|
||||
.incbin "gizmo.bin"
|
||||
GIZMO_GIZMO_OFFSET:
|
||||
.int 0
|
||||
GIZMO_GIZMO_SIZE:
|
||||
.int 27809
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
.global _GIZMO_GIZMO_OFFSET;
|
||||
.global _GIZMO_GIZMO_SIZE;
|
||||
|
||||
.global _GIZMO_PACKAGE
|
||||
.section __TEXT,__const
|
||||
_GIZMO_PACKAGE:
|
||||
.incbin "gizmo.bin"
|
||||
_GIZMO_GIZMO_OFFSET:
|
||||
.int 0
|
||||
_GIZMO_GIZMO_SIZE:
|
||||
.int 27809
|
||||
|
||||
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
#ifndef GIZMO_H_
|
||||
#define GIZMO_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
extern const uint8_t GIZMO_PACKAGE[];
|
||||
extern int GIZMO_GIZMO_OFFSET;
|
||||
extern int GIZMO_GIZMO_SIZE;
|
||||
}
|
||||
#define GIZMO_GIZMO_DATA (GIZMO_PACKAGE + GIZMO_GIZMO_OFFSET)
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
12
thermion_dart/native/include/material/unlit_fixed_size.S
Normal file
12
thermion_dart/native/include/material/unlit_fixed_size.S
Normal file
@@ -0,0 +1,12 @@
|
||||
.global UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET;
|
||||
.global UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE;
|
||||
|
||||
.global UNLIT_FIXED_SIZE_PACKAGE
|
||||
.section .rodata
|
||||
UNLIT_FIXED_SIZE_PACKAGE:
|
||||
.incbin "unlit_fixed_size.bin"
|
||||
UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET:
|
||||
.int 0
|
||||
UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE:
|
||||
.int 28235
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
.global _UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET;
|
||||
.global _UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE;
|
||||
|
||||
.global _UNLIT_FIXED_SIZE_PACKAGE
|
||||
.section __TEXT,__const
|
||||
_UNLIT_FIXED_SIZE_PACKAGE:
|
||||
.incbin "unlit_fixed_size.bin"
|
||||
_UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET:
|
||||
.int 0
|
||||
_UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE:
|
||||
.int 28235
|
||||
|
||||
BIN
thermion_dart/native/include/material/unlit_fixed_size.bin
Normal file
BIN
thermion_dart/native/include/material/unlit_fixed_size.bin
Normal file
Binary file not shown.
1422
thermion_dart/native/include/material/unlit_fixed_size.c
Normal file
1422
thermion_dart/native/include/material/unlit_fixed_size.c
Normal file
File diff suppressed because it is too large
Load Diff
13
thermion_dart/native/include/material/unlit_fixed_size.h
Normal file
13
thermion_dart/native/include/material/unlit_fixed_size.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef UNLIT_FIXED_SIZE_H_
|
||||
#define UNLIT_FIXED_SIZE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
extern "C" {
|
||||
extern const uint8_t UNLIT_FIXED_SIZE_PACKAGE[];
|
||||
extern int UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET;
|
||||
extern int UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE;
|
||||
}
|
||||
#define UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_DATA (UNLIT_FIXED_SIZE_PACKAGE + UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_OFFSET)
|
||||
|
||||
#endif
|
||||
@@ -1191,23 +1191,16 @@ namespace thermion
|
||||
return _engine->getCameraComponent(Entity::import(entity));
|
||||
}
|
||||
|
||||
void FilamentViewer::pick(View *view, uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y, View *view))
|
||||
bool FilamentViewer::isNonPickableEntity(EntityId entityId) {
|
||||
auto renderable = Entity::import(entityId);
|
||||
return _sceneManager->isGizmoEntity(renderable) || renderable == _imageEntity || renderable == _sceneManager->_gridOverlay->sphere() || _sceneManager->_gridOverlay->grid();
|
||||
}
|
||||
|
||||
void FilamentViewer::pick(View *view, uint32_t x, uint32_t y, PickCallback callback)
|
||||
{
|
||||
view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||
|
||||
if(_sceneManager->isGizmoEntity(result.renderable)) {
|
||||
Log("Gizmo entity, ignoring");
|
||||
return;
|
||||
}
|
||||
std::unordered_set<Entity, Entity::Hasher> nonPickableEntities = {
|
||||
_imageEntity,
|
||||
_sceneManager->_gridOverlay->sphere(),
|
||||
_sceneManager->_gridOverlay->grid(),
|
||||
};
|
||||
|
||||
if (nonPickableEntities.find(result.renderable) == nonPickableEntities.end()) {
|
||||
callback(Entity::smuggle(result.renderable), x, y, view);
|
||||
} });
|
||||
callback(Entity::smuggle(result.renderable), x, y, view, result.depth, result.fragCoords.x, result.fragCoords.y, result.fragCoords.z);
|
||||
});
|
||||
}
|
||||
|
||||
void FilamentViewer::unprojectTexture(EntityId entityId, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||
|
||||
@@ -7,31 +7,26 @@
|
||||
#include <filament/TransformManager.h>
|
||||
#include <gltfio/math.h>
|
||||
#include "SceneManager.hpp"
|
||||
#include "material/gizmo.h"
|
||||
#include "material/unlit_fixed_size.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
Gizmo::Gizmo(Engine *engine, View *view, Scene* scene) : _engine(engine), _view(view), _scene(scene)
|
||||
Gizmo::Gizmo(Engine *engine, View *view, Scene* scene, Material* material) : _engine(engine), _view(view), _scene(scene), _material(material)
|
||||
{
|
||||
|
||||
auto &entityManager = EntityManager::get();
|
||||
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
|
||||
_material =
|
||||
Material::Builder()
|
||||
.package(GIZMO_GIZMO_DATA, GIZMO_GIZMO_SIZE)
|
||||
.build(*_engine);
|
||||
|
||||
// First, create the black cube at the center
|
||||
// The axes widgets will be parented to this entity
|
||||
_entities[3] = entityManager.create();
|
||||
|
||||
_materialInstances[3] = _material->createInstance();
|
||||
_materialInstances[3]->setParameter("color", math::float4{0.0f, 0.0f, 0.0f, 1.0f}); // Black color
|
||||
_materialInstances[3]->setParameter("baseColorFactor", math::float4{0.0f, 0.0f, 0.0f, 1.0f}); // Black color
|
||||
|
||||
// Create center cube vertices
|
||||
float centerCubeSize = 0.01f;
|
||||
@@ -160,7 +155,7 @@ Gizmo::Gizmo(Engine *engine, View *view, Scene* scene) : _engine(engine), _view(
|
||||
break;
|
||||
}
|
||||
|
||||
_materialInstances[i]->setParameter("color", baseColor);
|
||||
_materialInstances[i]->setParameter("baseColorFactor", baseColor);
|
||||
|
||||
RenderableManager::Builder(1)
|
||||
.boundingBox({{-arrowWidth, -arrowWidth, 0},
|
||||
|
||||
@@ -33,9 +33,12 @@
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "UnprojectTexture.hpp"
|
||||
|
||||
#include "Gizmo.hpp"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "material/image.h"
|
||||
#include "material/unlit_fixed_size.h"
|
||||
}
|
||||
|
||||
namespace thermion
|
||||
@@ -53,8 +56,7 @@ namespace thermion
|
||||
Scene *scene,
|
||||
const char *uberArchivePath,
|
||||
Camera *mainCamera)
|
||||
:
|
||||
_resourceLoaderWrapper(resourceLoaderWrapper),
|
||||
: _resourceLoaderWrapper(resourceLoaderWrapper),
|
||||
_engine(engine),
|
||||
_scene(scene),
|
||||
_mainCamera(mainCamera)
|
||||
@@ -103,11 +105,16 @@ namespace thermion
|
||||
_scene->addEntity(_gridOverlay->sphere());
|
||||
_scene->addEntity(_gridOverlay->grid());
|
||||
|
||||
_gizmoMaterial =
|
||||
Material::Builder()
|
||||
.package(UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_DATA, UNLIT_FIXED_SIZE_UNLIT_FIXED_SIZE_SIZE)
|
||||
.build(*_engine);
|
||||
}
|
||||
|
||||
SceneManager::~SceneManager()
|
||||
{
|
||||
for(auto camera : _cameras) {
|
||||
for (auto camera : _cameras)
|
||||
{
|
||||
auto entity = camera->getEntity();
|
||||
_engine->destroyCameraComponent(entity);
|
||||
_engine->getEntityManager().destroy(entity);
|
||||
@@ -131,7 +138,13 @@ namespace thermion
|
||||
AssetLoader::destroy(&_assetLoader);
|
||||
}
|
||||
|
||||
bool SceneManager::isGizmoEntity(Entity entity) {
|
||||
Gizmo *SceneManager::createGizmo(View *view, Scene *scene)
|
||||
{
|
||||
return new Gizmo(_engine, view, scene, _gizmoMaterial);
|
||||
}
|
||||
|
||||
bool SceneManager::isGizmoEntity(Entity entity)
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
@@ -246,15 +259,16 @@ namespace thermion
|
||||
return eid;
|
||||
}
|
||||
|
||||
void SceneManager::setVisibilityLayer(EntityId entityId, int layer) {
|
||||
auto& rm = _engine->getRenderableManager();
|
||||
void SceneManager::setVisibilityLayer(EntityId entityId, int layer)
|
||||
{
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
auto renderable = rm.getInstance(utils::Entity::import(entityId));
|
||||
if(!renderable.isValid()) {
|
||||
if (!renderable.isValid())
|
||||
{
|
||||
Log("Warning: no renderable found");
|
||||
}
|
||||
|
||||
rm.setLayerMask(renderable, 0xFF, 1u << layer);
|
||||
|
||||
}
|
||||
|
||||
EntityId SceneManager::loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync)
|
||||
@@ -281,11 +295,13 @@ namespace thermion
|
||||
|
||||
_scene->addEntities(asset->getEntities(), entityCount);
|
||||
|
||||
auto & rm = _engine->getRenderableManager();
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
|
||||
for(int i=0; i < entityCount; i++) {
|
||||
for (int i = 0; i < entityCount; i++)
|
||||
{
|
||||
auto instance = rm.getInstance(asset->getEntities()[i]);
|
||||
if(!instance.isValid()) {
|
||||
if (!instance.isValid())
|
||||
{
|
||||
Log("No valid renderable for entity");
|
||||
continue;
|
||||
}
|
||||
@@ -304,13 +320,16 @@ namespace thermion
|
||||
_gltfResourceLoader->asyncUpdateLoad();
|
||||
}
|
||||
#else
|
||||
if(loadResourcesAsync) {
|
||||
if (loadResourcesAsync)
|
||||
{
|
||||
if (!_gltfResourceLoader->asyncBeginLoad(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
@@ -539,11 +558,13 @@ namespace thermion
|
||||
asset.second->getLightEntityCount());
|
||||
_assetLoader->destroyAsset(asset.second);
|
||||
}
|
||||
for(auto *texture : _textures) {
|
||||
for (auto *texture : _textures)
|
||||
{
|
||||
_engine->destroy(texture);
|
||||
}
|
||||
|
||||
for(auto *materialInstance : _materialInstances) {
|
||||
for (auto *materialInstance : _materialInstances)
|
||||
{
|
||||
_engine->destroy(materialInstance);
|
||||
}
|
||||
|
||||
@@ -661,7 +682,6 @@ namespace thermion
|
||||
|
||||
auto entity = Entity::import(entityId);
|
||||
|
||||
|
||||
if (_animationComponentManager->hasComponent(entity))
|
||||
{
|
||||
_animationComponentManager->removeComponent(entity);
|
||||
@@ -674,7 +694,8 @@ namespace thermion
|
||||
|
||||
_scene->remove(entity);
|
||||
|
||||
if(isGeometryEntity(entityId)) {
|
||||
if (isGeometryEntity(entityId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1412,7 +1433,7 @@ namespace thermion
|
||||
return texture;
|
||||
}
|
||||
|
||||
bool SceneManager::applyTexture(EntityId entityId, Texture *texture, const char* parameterName, int materialIndex)
|
||||
bool SceneManager::applyTexture(EntityId entityId, Texture *texture, const char *parameterName, int materialIndex)
|
||||
{
|
||||
auto entity = Entity::import(entityId);
|
||||
|
||||
@@ -1446,8 +1467,10 @@ namespace thermion
|
||||
return true;
|
||||
}
|
||||
|
||||
void SceneManager::destroyTexture(Texture* texture) {
|
||||
if(_textures.find(texture) == _textures.end()) {
|
||||
void SceneManager::destroyTexture(Texture *texture)
|
||||
{
|
||||
if (_textures.find(texture) == _textures.end())
|
||||
{
|
||||
Log("Warning: couldn't find texture");
|
||||
}
|
||||
_textures.erase(texture);
|
||||
@@ -1904,7 +1927,7 @@ namespace thermion
|
||||
tm.setTransform(transformInstance, newTransform);
|
||||
}
|
||||
|
||||
void SceneManager::queueRelativePositionUpdateFromViewportVector(View* view, EntityId entityId, float viewportCoordX, float viewportCoordY)
|
||||
void SceneManager::queueRelativePositionUpdateFromViewportVector(View *view, EntityId entityId, float viewportCoordX, float viewportCoordY)
|
||||
{
|
||||
// Get the camera and viewport
|
||||
const auto &camera = view->getCamera();
|
||||
@@ -1941,14 +1964,14 @@ namespace thermion
|
||||
auto entityPlaneInWorldSpace = camera.getModelMatrix() * entityPlaneInCameraSpace;
|
||||
|
||||
// Queue the position update (as a relative movement)
|
||||
|
||||
}
|
||||
|
||||
void SceneManager::queueTransformUpdates(EntityId* entities, math::mat4* transforms, int numEntities)
|
||||
void SceneManager::queueTransformUpdates(EntityId *entities, math::mat4 *transforms, int numEntities)
|
||||
{
|
||||
std::lock_guard lock(_mutex);
|
||||
|
||||
for(int i= 0; i < numEntities; i++) {
|
||||
for (int i = 0; i < numEntities; i++)
|
||||
{
|
||||
auto entity = entities[i];
|
||||
const auto &pos = _transformUpdates.find(entity);
|
||||
if (pos == _transformUpdates.end())
|
||||
@@ -2279,7 +2302,7 @@ namespace thermion
|
||||
}
|
||||
}
|
||||
|
||||
EntityId SceneManager::createGeometry(
|
||||
EntityId SceneManager::createGeometry(
|
||||
float *vertices,
|
||||
uint32_t numVertices,
|
||||
float *normals,
|
||||
@@ -2289,9 +2312,9 @@ EntityId SceneManager::createGeometry(
|
||||
uint16_t *indices,
|
||||
uint32_t numIndices,
|
||||
filament::RenderableManager::PrimitiveType primitiveType,
|
||||
filament::MaterialInstance* materialInstance,
|
||||
filament::MaterialInstance *materialInstance,
|
||||
bool keepData)
|
||||
{
|
||||
{
|
||||
auto geometry = std::make_unique<CustomGeometry>(vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, _engine);
|
||||
|
||||
auto entity = utils::EntityManager::get().create();
|
||||
@@ -2305,7 +2328,8 @@ EntityId SceneManager::createGeometry(
|
||||
|
||||
filament::Material *mat = nullptr;
|
||||
|
||||
if (!materialInstance) {
|
||||
if (!materialInstance)
|
||||
{
|
||||
Log("Using default ubershader material");
|
||||
filament::gltfio::MaterialKey config;
|
||||
|
||||
@@ -2339,7 +2363,8 @@ EntityId SceneManager::createGeometry(
|
||||
|
||||
materialInstance = createUbershaderMaterialInstance(config);
|
||||
|
||||
if(!materialInstance) {
|
||||
if (!materialInstance)
|
||||
{
|
||||
Log("Failed to create material instance");
|
||||
return Entity::smuggle(Entity());
|
||||
}
|
||||
@@ -2348,10 +2373,11 @@ EntityId SceneManager::createGeometry(
|
||||
// Set up texture and sampler if UVs are available
|
||||
if (uvs != nullptr && numUvs > 0)
|
||||
{
|
||||
if(materialInstance->getMaterial()->hasParameter("baseColorMap")) {
|
||||
// Create a default white texture
|
||||
static constexpr uint32_t textureSize = 1;
|
||||
static constexpr uint32_t white = 0x00ffffff;
|
||||
Texture* texture = Texture::Builder()
|
||||
Texture *texture = Texture::Builder()
|
||||
.width(textureSize)
|
||||
.height(textureSize)
|
||||
.levels(1)
|
||||
@@ -2371,6 +2397,7 @@ EntityId SceneManager::createGeometry(
|
||||
// Set the texture and sampler to the material instance
|
||||
materialInstance->setParameter("baseColorMap", texture, sampler);
|
||||
}
|
||||
}
|
||||
|
||||
builder.material(0, materialInstance);
|
||||
builder.build(*_engine, entity);
|
||||
@@ -2382,9 +2409,10 @@ EntityId SceneManager::createGeometry(
|
||||
_geometry.emplace(entityId, std::move(geometry));
|
||||
|
||||
return entityId;
|
||||
}
|
||||
}
|
||||
|
||||
MaterialInstance* SceneManager::getMaterialInstanceAt(EntityId entityId, int materialIndex) {
|
||||
MaterialInstance *SceneManager::getMaterialInstanceAt(EntityId entityId, int materialIndex)
|
||||
{
|
||||
auto entity = Entity::import(entityId);
|
||||
const auto &rm = _engine->getRenderableManager();
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
@@ -2436,7 +2464,7 @@ EntityId SceneManager::createGeometry(
|
||||
materialInstance->setParameter(property, value);
|
||||
}
|
||||
|
||||
void SceneManager::setMaterialProperty(EntityId entityId, int materialIndex, const char *property, filament::math::float4& value)
|
||||
void SceneManager::setMaterialProperty(EntityId entityId, int materialIndex, const char *property, filament::math::float4 &value)
|
||||
{
|
||||
auto entity = Entity::import(entityId);
|
||||
const auto &rm = _engine->getRenderableManager();
|
||||
@@ -2453,17 +2481,20 @@ EntityId SceneManager::createGeometry(
|
||||
Log("Parameter %s not found", property);
|
||||
return;
|
||||
}
|
||||
materialInstance->setParameter(property, filament::math::float4 { value.x, value.y, value.z, value.w });
|
||||
materialInstance->setParameter(property, filament::math::float4{value.x, value.y, value.z, value.w});
|
||||
}
|
||||
|
||||
void SceneManager::destroy(MaterialInstance* instance) {
|
||||
void SceneManager::destroy(MaterialInstance *instance)
|
||||
{
|
||||
_engine->destroy(instance);
|
||||
}
|
||||
|
||||
MaterialInstance* SceneManager::createUbershaderMaterialInstance(filament::gltfio::MaterialKey config) {
|
||||
filament::gltfio::UvMap uvmap {};
|
||||
auto * materialInstance = _ubershaderProvider->createMaterialInstance(&config, &uvmap);
|
||||
if(!materialInstance) {
|
||||
MaterialInstance *SceneManager::createUbershaderMaterialInstance(filament::gltfio::MaterialKey config)
|
||||
{
|
||||
filament::gltfio::UvMap uvmap{};
|
||||
auto *materialInstance = _ubershaderProvider->createMaterialInstance(&config, &uvmap);
|
||||
if (!materialInstance)
|
||||
{
|
||||
Log("Invalid material configuration");
|
||||
return nullptr;
|
||||
}
|
||||
@@ -2473,44 +2504,58 @@ EntityId SceneManager::createGeometry(
|
||||
return materialInstance;
|
||||
}
|
||||
|
||||
MaterialInstance* SceneManager::createUnlitMaterialInstance() {
|
||||
MaterialInstance *SceneManager::createUnlitFixedSizeMaterialInstance()
|
||||
{
|
||||
auto instance = _gizmoMaterial->createInstance();
|
||||
instance->setParameter("scale", 1.0f);
|
||||
return instance;
|
||||
}
|
||||
|
||||
MaterialInstance *SceneManager::createUnlitMaterialInstance()
|
||||
{
|
||||
UvMap uvmap;
|
||||
auto instance = _unlitMaterialProvider->createMaterialInstance(nullptr, &uvmap);
|
||||
instance->setParameter("uvScale", filament::math::float2 { 1.0f, 1.0f });
|
||||
instance->setParameter("uvScale", filament::math::float2{1.0f, 1.0f});
|
||||
_materialInstances.push_back(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
Camera* SceneManager::createCamera() {
|
||||
Camera *SceneManager::createCamera()
|
||||
{
|
||||
auto entity = EntityManager::get().create();
|
||||
auto camera = _engine->createCamera(entity);
|
||||
_cameras.push_back(camera);
|
||||
return camera;
|
||||
}
|
||||
|
||||
void SceneManager::destroyCamera(Camera* camera) {
|
||||
void SceneManager::destroyCamera(Camera *camera)
|
||||
{
|
||||
auto entity = camera->getEntity();
|
||||
_engine->destroyCameraComponent(entity);
|
||||
_engine->getEntityManager().destroy(entity);
|
||||
auto it = std::find(_cameras.begin(), _cameras.end(), camera);
|
||||
if(it != _cameras.end()) {
|
||||
if (it != _cameras.end())
|
||||
{
|
||||
_cameras.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
size_t SceneManager::getCameraCount() {
|
||||
size_t SceneManager::getCameraCount()
|
||||
{
|
||||
return _cameras.size() + 1;
|
||||
}
|
||||
|
||||
Camera* SceneManager::getCameraAt(size_t index) {
|
||||
if(index == 0) {
|
||||
Camera *SceneManager::getCameraAt(size_t index)
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
return _mainCamera;
|
||||
}
|
||||
if(index - 1 > _cameras.size() - 1) {
|
||||
if (index - 1 > _cameras.size() - 1)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return _cameras[index-1];
|
||||
return _cameras[index - 1];
|
||||
}
|
||||
|
||||
|
||||
} // namespace thermion
|
||||
|
||||
@@ -14,15 +14,6 @@ extern "C"
|
||||
using namespace filament;
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TGizmo* Gizmo_new(TEngine *tEngine, TView *tView, TScene *tScene)
|
||||
{
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
auto *engine = reinterpret_cast<Engine*>(tEngine);
|
||||
auto *scene = reinterpret_cast<Scene*>(tScene);
|
||||
auto gizmo = new Gizmo(engine, view, scene);
|
||||
return reinterpret_cast<TGizmo*>(gizmo);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_pick(TGizmo *tGizmo, uint32_t x, uint32_t y, GizmoPickCallback callback)
|
||||
{
|
||||
auto *gizmo = reinterpret_cast<Gizmo*>(tGizmo);
|
||||
|
||||
@@ -49,11 +49,16 @@ extern "C"
|
||||
viewer->destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *tViewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView))
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_pick(TViewer *tViewer, TView* tView, int x, int y, void (*callback)(EntityId entityId, int x, int y, TView *tView, float depth, float fragX, float fragY, float fragZ))
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
((FilamentViewer *)viewer)->pick(view, static_cast<uint32_t>(x), static_cast<uint32_t>(y), reinterpret_cast<void (*)(EntityId entityId, int x, int y, View *view)>(callback));
|
||||
((FilamentViewer *)viewer)->pick(view, static_cast<uint32_t>(x), static_cast<uint32_t>(y), reinterpret_cast<FilamentViewer::PickCallback>(callback));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool Viewer_isNonPickableEntity(TViewer *tViewer, EntityId entityId) {
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
return viewer->isNonPickableEntity(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer)
|
||||
@@ -168,6 +173,14 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances, keepData);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TGizmo* SceneManager_createGizmo(TSceneManager *tSceneManager, TView *tView, TScene *tScene) {
|
||||
auto sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
auto *scene = reinterpret_cast<Scene*>(tScene);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
auto gizmo = sceneManager->createGizmo(view, scene);
|
||||
return reinterpret_cast<TGizmo*>(gizmo);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_loadGlbFromBuffer(TSceneManager *sceneManager, const uint8_t *const data, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->loadGlbFromBuffer((const uint8_t *)data, length, 1, keepData, priority, layer, loadResourcesAsync);
|
||||
@@ -1021,6 +1034,12 @@ extern "C"
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *SceneManager_createUnlitFixedSizeMaterialInstance(TSceneManager *sceneManager)
|
||||
{
|
||||
auto *instance = ((SceneManager *)sceneManager)->createUnlitFixedSizeMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_material_instance(TSceneManager *sceneManager, TMaterialInstance *instance)
|
||||
{
|
||||
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance *>(instance));
|
||||
@@ -1042,6 +1061,10 @@ extern "C"
|
||||
reinterpret_cast<MaterialInstance *>(materialInstance)->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat(TMaterialInstance *materialInstance, const char *propertyName, double value)
|
||||
{
|
||||
reinterpret_cast<MaterialInstance *>(materialInstance)->setParameter(propertyName, static_cast<float>(value));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *tEngine, EntityId entityId)
|
||||
{
|
||||
|
||||
@@ -371,6 +371,16 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createUnlitFixedSizeMaterialInstanceRenderThread(TSceneManager *sceneManager, void (*callback)(TMaterialInstance*)) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto instance = SceneManager_createUnlitFixedSizeMaterialInstance(sceneManager);
|
||||
callback(instance);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager,
|
||||
const uint8_t *const data,
|
||||
size_t length,
|
||||
|
||||
@@ -62,7 +62,7 @@ add_executable(${MODULE_NAME}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/camutils/Manipulator.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../src/camutils/Bookmark.cpp"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../include/material/image.c"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../include/material/gizmo.c"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/../include/material/unlit_fixed_size.c"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/cpp/ThermionDartWebApi.cpp"
|
||||
)
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: thermion_dart
|
||||
description: 3D rendering toolkit for Dart.
|
||||
version: 0.2.1-dev.0.0.12
|
||||
version: 0.2.1-dev.0.0.16
|
||||
homepage: https://thermion.dev
|
||||
repository: https://github.com/nmfisher/thermion
|
||||
|
||||
@@ -18,6 +18,7 @@ dependencies:
|
||||
web: ^1.0.0
|
||||
logging: ^1.2.0
|
||||
http: ^1.2.2
|
||||
path: ^1.9.0
|
||||
|
||||
dev_dependencies:
|
||||
ffigen: ^13.0.0
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/events.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'helpers.dart';
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
@@ -7,7 +11,6 @@ void main() async {
|
||||
final testHelper = TestHelper("integration");
|
||||
|
||||
group('camera', () {
|
||||
|
||||
test('getCameraModelMatrix, getCameraPosition, rotation', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
var matrix = await viewer.getCameraModelMatrix();
|
||||
@@ -50,7 +53,6 @@ void main() async {
|
||||
expect(position.y, closeTo(4.0, 1e-6));
|
||||
expect(position.z, closeTo(5.0, 1e-6));
|
||||
await viewer.dispose();
|
||||
|
||||
});
|
||||
|
||||
test('getCameraProjectionMatrix', () async {
|
||||
@@ -62,11 +64,11 @@ void main() async {
|
||||
|
||||
test('getCameraCullingProjectionMatrix', () async {
|
||||
throw Exception("TODO");
|
||||
// ignore: dead_code
|
||||
var viewer = await testHelper.createViewer();
|
||||
var matrix = await viewer.getCameraCullingProjectionMatrix();
|
||||
print(matrix);
|
||||
await viewer.dispose();
|
||||
|
||||
});
|
||||
|
||||
test('getCameraFrustum', () async {
|
||||
@@ -92,13 +94,37 @@ void main() async {
|
||||
var camera = await viewer.getMainCamera();
|
||||
await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
await camera.setProjection(Projection.Orthographic, -0.05, 0.05, -0.05, 0.05, 0.05, 10000);
|
||||
await testHelper.capture(
|
||||
viewer, "camera_set_orthographic_projection");
|
||||
await camera.setProjection(
|
||||
Projection.Orthographic, -0.05, 0.05, -0.05, 0.05, 0.05, 10000);
|
||||
await testHelper.capture(viewer, "camera_set_orthographic_projection");
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('set custom projection/culling matrix', () async {
|
||||
test('set perspective projection/culling matrix', () async {
|
||||
var viewer = await testHelper.createViewer(
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 4));
|
||||
var camera = await viewer.getMainCamera();
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
var fovY = pi / 2;
|
||||
await camera.setProjectionMatrixWithCulling(
|
||||
makePerspectiveMatrix(fovY, 1.0, 0.05, 10000), 0.05, 10000);
|
||||
|
||||
await testHelper.capture(
|
||||
viewer, "camera_set_perspective_projection_culling_matrix_object_fov90");
|
||||
|
||||
// cube no longer visible when the far plane is moved closer to camera so cube is outside
|
||||
fovY = 2*(pi/3);
|
||||
await camera.setProjectionMatrixWithCulling(
|
||||
makePerspectiveMatrix(fovY, 1.0, 0.05, 10000), 0.05, 10000);
|
||||
|
||||
await testHelper.capture(
|
||||
viewer, "camera_set_perspective_projection_culling_matrix_object_fov120");
|
||||
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('set custom projection/culling matrix (orthographic)', () async {
|
||||
var viewer = await testHelper.createViewer(
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 4));
|
||||
var camera = await viewer.getMainCamera();
|
||||
|
||||
16
thermion_dart/test/dummy_tests.dart
Normal file
16
thermion_dart/test/dummy_tests.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
// just for investigating crashes on GitHub actions
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
void main() async {
|
||||
group("test", () {
|
||||
test("test", () async {
|
||||
print("Creating test helper");
|
||||
final testHelper = TestHelper("dummy");
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
expect(1, 1);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:io';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
@@ -10,7 +12,6 @@ import 'package:thermion_dart/src/utils/src/dart_resources.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/view.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
@@ -72,19 +73,22 @@ class TestHelper {
|
||||
|
||||
TestHelper(String dir) {
|
||||
final packageUri = findPackageRoot('thermion_dart');
|
||||
print("Package URIL $packageUri");
|
||||
testDir = Directory("${packageUri.toFilePath()}/test").path;
|
||||
print("Test dir : $packageUri");
|
||||
|
||||
outDir = Directory("$testDir/output/${dir}");
|
||||
print("Out dir : $packageUri");
|
||||
// outDir.deleteSync(recursive: true);
|
||||
outDir.createSync(recursive: true);
|
||||
if(Platform.isMacOS) {
|
||||
print("Created out dir : $packageUri");
|
||||
if (Platform.isMacOS) {
|
||||
DynamicLibrary.open('${testDir}/libThermionTextureSwift.dylib');
|
||||
}
|
||||
}
|
||||
|
||||
Future capture(ThermionViewer viewer, String outputFilename,
|
||||
{View? view, SwapChain? swapChain, RenderTarget? renderTarget}) async {
|
||||
|
||||
await Future.delayed(Duration(milliseconds: 10));
|
||||
var outPath = p.join(outDir.path, "$outputFilename.bmp");
|
||||
|
||||
@@ -101,9 +105,6 @@ class TestHelper {
|
||||
}
|
||||
|
||||
Future<ThermionTextureSwift> createTexture(int width, int height) async {
|
||||
final packageUri = findPackageRoot('thermion_dart');
|
||||
var testDir = Directory("${packageUri.toFilePath()}/test").path;
|
||||
|
||||
final object = ThermionTextureSwift.new1();
|
||||
object.initWithWidth_height_(width, height);
|
||||
return object;
|
||||
@@ -114,24 +115,29 @@ class TestHelper {
|
||||
Vector3? cameraPosition,
|
||||
viewportDimensions = (width: 500, height: 500)}) async {
|
||||
final resourceLoader = calloc<ResourceLoaderWrapper>(1);
|
||||
print("resourceLoader");
|
||||
var loadToOut = NativeCallable<
|
||||
Void Function(Pointer<Char>,
|
||||
Pointer<ResourceBuffer>)>.listener(DartResourceLoader.loadResource);
|
||||
|
||||
print("loadToOut");
|
||||
resourceLoader.ref.loadToOut = loadToOut.nativeFunction;
|
||||
print("set ref");
|
||||
var freeResource = NativeCallable<Void Function(ResourceBuffer)>.listener(
|
||||
DartResourceLoader.freeResource);
|
||||
print("freeResource");
|
||||
resourceLoader.ref.freeResource = freeResource.nativeFunction;
|
||||
|
||||
print("set freeResource ref");
|
||||
var viewer = ThermionViewerFFI(resourceLoader: resourceLoader.cast<Void>());
|
||||
|
||||
print("created viewer");
|
||||
await viewer.initialized;
|
||||
swapChain = await viewer.createHeadlessSwapChain(
|
||||
viewportDimensions.width, viewportDimensions.height);
|
||||
print("created headless swapchain");
|
||||
|
||||
await viewer.updateViewportAndCameraProjection(
|
||||
viewportDimensions.width.toDouble(),
|
||||
viewportDimensions.height.toDouble());
|
||||
print("updated camera");
|
||||
if (bg != null) {
|
||||
await viewer.setBackgroundColor(
|
||||
bg.r.toDouble(), bg.g.toDouble(), bg.b.toDouble(), bg.a.toDouble());
|
||||
@@ -191,7 +197,7 @@ Future<Uint8List> pixelBufferToBmp(
|
||||
}
|
||||
|
||||
Future<Uint8List> pixelsToPng(Uint8List pixelBuffer, int width, int height,
|
||||
{bool linearToSrgb = false}) async {
|
||||
{bool linearToSrgb = false, bool invertAces = false}) async {
|
||||
final image = img.Image(width: width, height: height);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
@@ -203,7 +209,6 @@ Future<Uint8List> pixelsToPng(Uint8List pixelBuffer, int width, int height,
|
||||
int a = pixelBuffer[pixelIndex + 3];
|
||||
|
||||
// Apply inverse ACES tone mapping
|
||||
bool invertAces = false;
|
||||
if (invertAces) {
|
||||
r = _inverseACESToneMapping(r);
|
||||
g = _inverseACESToneMapping(g);
|
||||
|
||||
@@ -1,782 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:thermion_dart/src/viewer/src/events.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_viewer_ffi.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
void main() async {
|
||||
final testHelper = TestHelper("integration");
|
||||
|
||||
group('background', () {
|
||||
test('set background color to solid green', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0);
|
||||
await testHelper.capture(viewer, "set_background_color_to_solid_green");
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('set background color to full transparency', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 0.0);
|
||||
await testHelper.capture(
|
||||
viewer, "set_background_color_to_transparent_green");
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('set background image', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundImage(
|
||||
"file:///${testHelper.testDir}/assets/cube_texture_512x512.png");
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
await testHelper.capture(viewer, "set_background_image");
|
||||
await viewer.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
group("scene update events", () {
|
||||
test('add light fires SceneUpdateEvent', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
var light = DirectLight(
|
||||
type: LightType.POINT,
|
||||
color: 6500,
|
||||
intensity: 1000000,
|
||||
position: Vector3(0, 0.6, 0.6),
|
||||
direction: Vector3(0, 0, 0),
|
||||
falloffRadius: 2.0);
|
||||
|
||||
late StreamSubscription listener;
|
||||
listener = viewer.sceneUpdated.listen((updateEvent) {
|
||||
var wasSuccess = updateEvent.eventType == EventType.EntityAdded &&
|
||||
updateEvent.addedEntityType == EntityType.DirectLight &&
|
||||
updateEvent.getDirectLight() == light;
|
||||
success.complete(wasSuccess);
|
||||
listener.cancel();
|
||||
});
|
||||
await viewer.addDirectLight(light);
|
||||
expect(await success.future, true);
|
||||
});
|
||||
|
||||
test('remove light fires SceneUpdateEvent', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
var light = await viewer.addDirectLight(DirectLight.point());
|
||||
|
||||
late StreamSubscription listener;
|
||||
listener = viewer.sceneUpdated.listen((updateEvent) {
|
||||
var wasSuccess = updateEvent.eventType == EventType.EntityRemoved &&
|
||||
updateEvent.entity == light;
|
||||
success.complete(wasSuccess);
|
||||
listener.cancel();
|
||||
});
|
||||
|
||||
await viewer.removeLight(light);
|
||||
|
||||
expect(await success.future, true);
|
||||
});
|
||||
|
||||
test('add geometry fires SceneUpdateEvent', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
var geometry = GeometryHelper.cube();
|
||||
|
||||
late StreamSubscription listener;
|
||||
listener = viewer.sceneUpdated.listen((updateEvent) {
|
||||
var wasSuccess = updateEvent.eventType == EventType.EntityAdded &&
|
||||
updateEvent.addedEntityType == EntityType.Geometry &&
|
||||
updateEvent.getAsGeometry() == geometry;
|
||||
success.complete(wasSuccess);
|
||||
listener.cancel();
|
||||
});
|
||||
await viewer.createGeometry(geometry);
|
||||
expect(await success.future, true);
|
||||
});
|
||||
|
||||
test('remove geometry fires SceneUpdateEvent', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
var geometry = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final success = Completer<bool>();
|
||||
|
||||
late StreamSubscription listener;
|
||||
listener = viewer.sceneUpdated.listen((updateEvent) {
|
||||
var wasSuccess = updateEvent.eventType == EventType.EntityRemoved &&
|
||||
updateEvent.entity == geometry;
|
||||
success.complete(wasSuccess);
|
||||
listener.cancel();
|
||||
});
|
||||
|
||||
await viewer.removeEntity(geometry);
|
||||
|
||||
expect(await success.future, true);
|
||||
});
|
||||
|
||||
test('loadGlb fires SceneUpdateEvent', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
|
||||
late StreamSubscription listener;
|
||||
|
||||
final uri = "${testHelper.testDir}/cube.glb";
|
||||
|
||||
listener = viewer.sceneUpdated.listen((updateEvent) {
|
||||
var wasSuccess = updateEvent.eventType == EventType.EntityAdded &&
|
||||
updateEvent.addedEntityType == EntityType.Gltf &&
|
||||
updateEvent.getAsGLTF().uri == uri;
|
||||
success.complete(wasSuccess);
|
||||
listener.cancel();
|
||||
});
|
||||
await viewer.loadGlb(uri, keepData: false);
|
||||
expect(await success.future, true);
|
||||
});
|
||||
|
||||
test('remove glb fires SceneUpdateEvent', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
final uri = "${testHelper.testDir}/cube.glb";
|
||||
var entity = await viewer.loadGlb(uri, keepData: false);
|
||||
|
||||
final success = Completer<bool>();
|
||||
|
||||
late StreamSubscription listener;
|
||||
listener = viewer.sceneUpdated.listen((updateEvent) {
|
||||
var wasSuccess = updateEvent.eventType == EventType.EntityRemoved &&
|
||||
updateEvent.entity == entity;
|
||||
success.complete(wasSuccess);
|
||||
listener.cancel();
|
||||
});
|
||||
await viewer.removeEntity(entity);
|
||||
expect(await success.future, true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
group("MaterialInstance", () {
|
||||
test('disable depth write', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.addDirectLight(
|
||||
DirectLight.sun(direction: Vector3(0, 0, -1)..normalize()));
|
||||
|
||||
final cube1 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
var materialInstance = await viewer.getMaterialInstanceAt(cube1, 0);
|
||||
|
||||
final cube2 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube2, "baseColorFactor", 0, 0, 1, 0, 1);
|
||||
await viewer.setPosition(cube2, 1.0, 0.0, -1.0);
|
||||
|
||||
expect(materialInstance, isNotNull);
|
||||
|
||||
// with depth write enabled on both materials, cube2 renders behind the white cube
|
||||
await testHelper.capture(viewer, "material_instance_depth_write_enabled");
|
||||
|
||||
// if we disable depth write on cube1, then cube2 will always appear in front
|
||||
// (relying on insertion order)
|
||||
materialInstance!.setDepthWriteEnabled(false);
|
||||
await testHelper.capture(
|
||||
viewer, "material_instance_depth_write_disabled");
|
||||
|
||||
// set priority for the cube1 cube to 7 (render) last, cube1 renders in front
|
||||
await viewer.setPriority(cube1, 7);
|
||||
await testHelper.capture(
|
||||
viewer, "material_instance_depth_write_disabled_with_priority");
|
||||
});
|
||||
});
|
||||
|
||||
// test('create instance from glb when keepData is true', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
// await viewer.transformToUnitCube(model);
|
||||
// var instance = await viewer.createInstance(model);
|
||||
// await viewer.setPosition(instance, 0.5, 0.5, -0.5);
|
||||
// await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
// await viewer.setCameraPosition(0, 1, 5);
|
||||
// await viewer
|
||||
// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
// await viewer.setRendering(true);
|
||||
// await testHelper.capture(viewer, "glb_create_instance");
|
||||
// await viewer.setRendering(false);
|
||||
// });
|
||||
|
||||
// test('create instance from glb fails when keepData is false', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: false);
|
||||
// bool thrown = false;
|
||||
// try {
|
||||
// await viewer.createInstance(model);
|
||||
// } catch (err) {
|
||||
// thrown = true;
|
||||
// }
|
||||
// expect(thrown, true);
|
||||
// });
|
||||
// });
|
||||
|
||||
// group('Skinning & animations', () {
|
||||
// test('get bone names', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb");
|
||||
// var names = await viewer.getBoneNames(model);
|
||||
// expect(names.first, "Bone");
|
||||
// });
|
||||
|
||||
// test('reset bones', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb");
|
||||
// await viewer.resetBones(model);
|
||||
// });
|
||||
// test('set from BVH', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb");
|
||||
// var animation = BVHParser.parse(
|
||||
// File("${testHelper.testDir}/assets/animation.bvh").readAsStringSync(),
|
||||
// boneRegex: RegExp(r"Bone$"));
|
||||
// await viewer.addBoneAnimation(model, animation);
|
||||
// });
|
||||
|
||||
// test('fade in/out', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/assets/shapes.glb");
|
||||
// var animation = BVHParser.parse(
|
||||
// File("${testHelper.testDir}/assets/animation.bvh").readAsStringSync(),
|
||||
// boneRegex: RegExp(r"Bone$"));
|
||||
// await viewer.addBoneAnimation(model, animation,
|
||||
// fadeInInSecs: 0.5, fadeOutInSecs: 0.5);
|
||||
// await Future.delayed(Duration(seconds: 1));
|
||||
// });
|
||||
|
||||
group("materials", () {
|
||||
test('set float4 material property for custom geometry', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
var light = await viewer.addLight(
|
||||
LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
await testHelper.capture(viewer, "set_material_float4_pre");
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
|
||||
await testHelper.capture(viewer, "set_material_float4_post");
|
||||
});
|
||||
test('set float material property for custom geometry', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
var light = await viewer.addLight(
|
||||
LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
// this won't actually do anything because the default ubershader doesn't use specular/glossiness
|
||||
// but we can at least check that the call succeeds
|
||||
await testHelper.capture(viewer, "set_material_specular_pre");
|
||||
await viewer.setMaterialPropertyFloat(cube, "specularFactor", 0, 0.0);
|
||||
await testHelper.capture(viewer, "set_material_specular_post");
|
||||
});
|
||||
|
||||
test('set float material property (roughness) for custom geometry',
|
||||
() async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
var light = await viewer.addLight(
|
||||
LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
// this won't actually do anything because the default ubershader doesn't use specular/glossiness
|
||||
// but we can at least check that the call succeeds
|
||||
await testHelper.capture(viewer, "set_material_roughness_pre");
|
||||
|
||||
await viewer.setMaterialPropertyFloat(cube, "metallicFactor", 0, 0.0);
|
||||
await viewer.setMaterialPropertyFloat(cube, "roughnessFactor", 0, 0.0);
|
||||
await testHelper.capture(viewer, "set_material_roughness_post");
|
||||
});
|
||||
});
|
||||
|
||||
group("transforms & parenting", () {
|
||||
test('set multiple transforms simultaneously with setTransforms', () async {
|
||||
var viewer =
|
||||
await testHelper.createViewer(bg: kRed, cameraPosition: Vector3(0, 0, 5));
|
||||
final cube1 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final cube2 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
await viewer.queueTransformUpdates([
|
||||
cube1,
|
||||
cube2
|
||||
], [
|
||||
Matrix4.translation(Vector3(-1, 0, 0)),
|
||||
Matrix4.translation(Vector3(1, 0, 0))
|
||||
]);
|
||||
|
||||
await viewer.render(testHelper.swapChain);
|
||||
|
||||
await testHelper.capture(viewer, "set_multiple_transforms");
|
||||
});
|
||||
|
||||
test('getParent and getAncestor both return null when entity has no parent',
|
||||
() async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
expect(await viewer.getParent(cube), isNull);
|
||||
expect(await viewer.getAncestor(cube), isNull);
|
||||
});
|
||||
|
||||
test(
|
||||
'getParent returns the parent entity after one has been set via setParent',
|
||||
() async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final cube1 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
final cube2 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
await viewer.setParent(cube1, cube2);
|
||||
|
||||
final parent = await viewer.getParent(cube1);
|
||||
|
||||
expect(parent, cube2);
|
||||
});
|
||||
|
||||
test('getAncestor returns the ultimate parent entity', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final grandparent = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final parent = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final child = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
await viewer.setParent(child, parent);
|
||||
await viewer.setParent(parent, grandparent);
|
||||
|
||||
expect(await viewer.getAncestor(child), grandparent);
|
||||
});
|
||||
|
||||
test('set position based on screenspace coord', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
print(await viewer.getCameraFov(true));
|
||||
await viewer.createIbl(1.0, 1.0, 1.0, 1000);
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
// Create the cube geometry
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
// await viewer.setPosition(cube, -0.05, 0.04, 5.9);
|
||||
// await viewer.setPosition(cube, -2.54, 2.54, 0);
|
||||
await viewer.queuePositionUpdateFromViewportCoords(cube, 0, 0);
|
||||
|
||||
// we need an explicit render call here to process the transform queue
|
||||
await viewer.render(testHelper.swapChain);
|
||||
|
||||
await testHelper.capture(viewer, "set_position_from_viewport_coords");
|
||||
});
|
||||
});
|
||||
|
||||
group("layers & overlays", () {
|
||||
test('enable grid overlay', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(0, 0, 0, 1);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setCameraPosition(0, 2, 0);
|
||||
await testHelper.capture(viewer, "grid_overlay_default");
|
||||
await viewer.setLayerVisibility(7, true);
|
||||
await testHelper.capture(viewer, "grid_overlay_enabled");
|
||||
await viewer.setLayerVisibility(7, false);
|
||||
await testHelper.capture(viewer, "grid_overlay_disabled");
|
||||
});
|
||||
|
||||
test('load glb from buffer with layer', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setBackgroundColor(1, 0, 1, 1);
|
||||
await viewer.setCameraPosition(0, 2, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var buffer = File("${testHelper.testDir}/cube.glb").readAsBytesSync();
|
||||
var model = await viewer.loadGlbFromBuffer(buffer, layer: 1);
|
||||
await testHelper.capture(
|
||||
viewer, "load_glb_from_buffer_with_layer_disabled");
|
||||
await viewer.setLayerVisibility(1, true);
|
||||
await testHelper.capture(
|
||||
viewer, "load_glb_from_buffer_with_layer_enabled");
|
||||
});
|
||||
|
||||
test('change layer visibility at runtime', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setBackgroundColor(1, 0, 1, 1);
|
||||
await viewer.setCameraPosition(0, 2, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
await testHelper.capture(
|
||||
viewer, "change_layer_visibility_at_runtime_default");
|
||||
|
||||
// all entities set to layer 0 by default, so this should now be invisible
|
||||
await viewer.setLayerVisibility(0, false);
|
||||
await testHelper.capture(
|
||||
viewer, "change_layer_visibility_at_runtime_layer0_invisible");
|
||||
|
||||
// now change the visibility layer to 5, should be invisible
|
||||
await viewer.setVisibilityLayer(cube, 5);
|
||||
await testHelper.capture(
|
||||
viewer, "change_layer_visibility_at_runtime_layer5_invisible");
|
||||
|
||||
// now toggle layer 5 visibility, cube should now be visible
|
||||
await viewer.setLayerVisibility(5, true);
|
||||
await testHelper.capture(
|
||||
viewer, "change_layer_visibility_at_runtime_layer5_visible");
|
||||
});
|
||||
});
|
||||
|
||||
// test('point light', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb");
|
||||
// await viewer.transformToUnitCube(model);
|
||||
// var light = await viewer.addLight(
|
||||
// LightType.POINT, 6500, 1000000, 0, 2, 0, 0, -1, 0,
|
||||
// falloffRadius: 10.0);
|
||||
// await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0);
|
||||
// await viewer.setCameraPosition(0, 1, 5);
|
||||
// await viewer
|
||||
// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
// await viewer.setRendering(true);
|
||||
// await testHelper.capture(viewer, "point_light");
|
||||
// await viewer.setRendering(false);
|
||||
// });
|
||||
|
||||
// test('set point light position', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb");
|
||||
// await viewer.transformToUnitCube(model);
|
||||
// var light = await viewer.addLight(
|
||||
// LightType.POINT, 6500, 1000000, 0, 2, 0, 0, -1, 0,
|
||||
// falloffRadius: 10.0);
|
||||
// await viewer.setLightPosition(light, 0.5, 2, 0);
|
||||
// await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0);
|
||||
// await viewer.setCameraPosition(0, 1, 5);
|
||||
// await viewer
|
||||
// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
// await viewer.setRendering(true);
|
||||
// await testHelper.capture(viewer, "move_point_light");
|
||||
// await viewer.setRendering(false);
|
||||
// });
|
||||
|
||||
// test('directional light', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb");
|
||||
// await viewer.transformToUnitCube(model);
|
||||
// var light = await viewer.addLight(
|
||||
// LightType.SUN, 6500, 1000000, 0, 0, 0, 0, -1, 0);
|
||||
// await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0);
|
||||
// await viewer.setCameraPosition(0, 1, 5);
|
||||
// await viewer
|
||||
// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
// await viewer.setRendering(true);
|
||||
// await testHelper.capture(viewer, "directional_light");
|
||||
// await viewer.setRendering(false);
|
||||
// });
|
||||
|
||||
// test('set directional light direction', () async {
|
||||
// var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb");
|
||||
// await viewer.transformToUnitCube(model);
|
||||
// var light = await viewer.addLight(
|
||||
// LightType.SUN, 6500, 1000000, 0, 0, 0, 0, -1, 0);
|
||||
// await viewer.setLightDirection(light, Vector3(-1, -1, -1));
|
||||
// await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0);
|
||||
// await viewer.setCameraPosition(0, 1, 5);
|
||||
// await viewer
|
||||
// .setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
// await viewer.setRendering(true);
|
||||
// await testHelper.capture(viewer, "set_directional_light_direction");
|
||||
// await viewer.setRendering(false);
|
||||
// });
|
||||
|
||||
group("stencil", () {
|
||||
test('set stencil highlight for glb', () async {
|
||||
final viewer = await testHelper.createViewer();
|
||||
var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
await viewer.setPostProcessing(true);
|
||||
|
||||
var light = await viewer.addLight(
|
||||
LightType.SUN, 6500, 1000000, 0, 0, 0, 0, -1, 0);
|
||||
await viewer.setLightDirection(light, Vector3(0, 1, -1));
|
||||
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0);
|
||||
await viewer.setCameraPosition(0, -1, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), pi / 8));
|
||||
await viewer.setStencilHighlight(model);
|
||||
await testHelper.capture(viewer, "stencil_highlight_glb");
|
||||
});
|
||||
|
||||
test('set stencil highlight for geometry', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 2, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
await viewer.setStencilHighlight(cube);
|
||||
|
||||
await testHelper.capture(viewer, "stencil_highlight_geometry");
|
||||
|
||||
await viewer.removeStencilHighlight(cube);
|
||||
|
||||
await testHelper.capture(viewer, "stencil_highlight_geometry_remove");
|
||||
});
|
||||
|
||||
test('set stencil highlight for gltf asset', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 1, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var cube1 = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
await viewer.transformToUnitCube(cube1);
|
||||
|
||||
await viewer.setStencilHighlight(cube1);
|
||||
|
||||
await testHelper.capture(viewer, "stencil_highlight_gltf");
|
||||
|
||||
await viewer.removeStencilHighlight(cube1);
|
||||
|
||||
await testHelper.capture(viewer, "stencil_highlight_gltf_removed");
|
||||
});
|
||||
|
||||
test('set stencil highlight for multiple geometry ', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 1, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var cube1 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
var cube2 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
await viewer.setPosition(cube2, 0.5, 0.5, 0);
|
||||
await viewer.setStencilHighlight(cube1);
|
||||
await viewer.setStencilHighlight(cube2, r: 0.0, g: 0.0, b: 1.0);
|
||||
|
||||
await testHelper.capture(viewer, "stencil_highlight_multiple_geometry");
|
||||
|
||||
await viewer.removeStencilHighlight(cube1);
|
||||
await viewer.removeStencilHighlight(cube2);
|
||||
|
||||
await testHelper.capture(
|
||||
viewer, "stencil_highlight_multiple_geometry_removed");
|
||||
});
|
||||
|
||||
test('set stencil highlight for multiple gltf assets ', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setBackgroundColor(0.0, 1.0, 0.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 1, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var cube1 = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
await viewer.transformToUnitCube(cube1);
|
||||
var cube2 = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
await viewer.transformToUnitCube(cube2);
|
||||
await viewer.setPosition(cube2, 0.5, 0.5, 0);
|
||||
await viewer.setStencilHighlight(cube1);
|
||||
await viewer.setStencilHighlight(cube2, r: 0.0, g: 0.0, b: 1.0);
|
||||
|
||||
await testHelper.capture(viewer, "stencil_highlight_multiple_geometry");
|
||||
|
||||
await viewer.removeStencilHighlight(cube1);
|
||||
await viewer.removeStencilHighlight(cube2);
|
||||
|
||||
await testHelper.capture(
|
||||
viewer, "stencil_highlight_multiple_geometry_removed");
|
||||
});
|
||||
});
|
||||
|
||||
group("texture", () {
|
||||
test("create/apply/dispose texture", () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync();
|
||||
|
||||
var texture = await viewer.createTexture(textureData);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 0.0, 1.0);
|
||||
await viewer.addDirectLight(
|
||||
DirectLight.sun(direction: Vector3(0, -10, -1)..normalize()));
|
||||
await viewer.addDirectLight(DirectLight.spot(
|
||||
intensity: 1000000,
|
||||
position: Vector3(0, 0, 1.5),
|
||||
direction: Vector3(0, 0, -1)..normalize(),
|
||||
falloffRadius: 10,
|
||||
spotLightConeInner: 1,
|
||||
spotLightConeOuter: 1));
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
var materialInstance =
|
||||
await viewer.createUbershaderMaterialInstance(unlit: true);
|
||||
var cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
|
||||
await viewer.applyTexture(texture, cube,
|
||||
materialIndex: 0, parameterName: "baseColorMap");
|
||||
|
||||
await testHelper.capture(viewer, "texture_applied_to_geometry");
|
||||
|
||||
await viewer.removeEntity(cube);
|
||||
await viewer.destroyTexture(texture);
|
||||
});
|
||||
});
|
||||
|
||||
// group("unproject", () {
|
||||
// test("unproject", () async {
|
||||
// final dimensions = (width: 1280, height: 768);
|
||||
|
||||
// var viewer = await testHelper.createViewer(viewportDimensions: dimensions);
|
||||
// await viewer.setPostProcessing(false);
|
||||
// // await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
// await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
// // await viewer.createIbl(1.0, 1.0, 1.0, 100000);
|
||||
// await viewer.addLight(LightType.SUN, 6500, 100000, -2, 0, 0, 1, -1, 0);
|
||||
// await viewer.addLight(LightType.SPOT, 6500, 500000, 0, 0, 2, 0, 0, -1,
|
||||
// falloffRadius: 10, spotLightConeInner: 1.0, spotLightConeOuter: 2.0);
|
||||
|
||||
// await viewer.setCameraPosition(-3, 4, 6);
|
||||
// await viewer.setCameraRotation(
|
||||
// Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) *
|
||||
// Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 6));
|
||||
// var cube =
|
||||
// await viewer.createGeometry(GeometryHelper.cube(), keepData: true);
|
||||
// await viewer.setMaterialPropertyFloat4(
|
||||
// cube, "baseColorFactor", 0, 1.0, 1.0, 1.0, 1.0);
|
||||
// var textureData =
|
||||
// File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync();
|
||||
// var texture = await viewer.createTexture(textureData);
|
||||
// await viewer.applyTexture(texture, cube,
|
||||
// materialIndex: 0, parameterName: "baseColorMap");
|
||||
|
||||
// var numFrames = 60;
|
||||
|
||||
// // first do the render
|
||||
// for (int i = 0; i < numFrames; i++) {
|
||||
// await viewer.setCameraPosition(-3 + (i / numFrames * 2), 4, 6);
|
||||
|
||||
// await viewer.setCameraRotation(
|
||||
// Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) *
|
||||
// Quaternion.axisAngle(
|
||||
// Vector3(1, 0, 0), -pi / 6 - (i / numFrames * pi / 6)));
|
||||
|
||||
// var rendered = await testHelper.capture(viewer, "unproject_render$i");
|
||||
// var renderPng =
|
||||
// await pixelsToPng(rendered, dimensions.width, dimensions.height);
|
||||
|
||||
// File("${outDir.path}/unproject_render${i}.png")
|
||||
// .writeAsBytesSync(renderPng);
|
||||
// }
|
||||
|
||||
// // then go off and convert the video
|
||||
|
||||
// // now unproject the render back onto the geometry
|
||||
// final textureSize = (width: 1280, height: 768);
|
||||
// var pixels = <Uint8List>[];
|
||||
// // note we skip the first frame
|
||||
// for (int i = 0; i < numFrames; i++) {
|
||||
// await viewer.setCameraPosition(-3 + (i / numFrames * 2), 4, 6);
|
||||
|
||||
// await viewer.setCameraRotation(
|
||||
// Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) *
|
||||
// Quaternion.axisAngle(
|
||||
// Vector3(1, 0, 0), -pi / 6 - (i / numFrames * pi / 6)));
|
||||
|
||||
// var input = pngToPixelBuffer(File(
|
||||
// "${outDir.path}/a8c317af-6081-4848-8a06-f6b69bc57664_${i + 1}.png")
|
||||
// .readAsBytesSync());
|
||||
// var pixelBuffer = await (await viewer as ThermionViewerFFI).unproject(
|
||||
// cube,
|
||||
// input,
|
||||
// dimensions.width,
|
||||
// dimensions.height,
|
||||
// textureSize.width,
|
||||
// textureSize.height);
|
||||
|
||||
// // var png = await pixelsToPng(Uint8List.fromList(pixelBuffer),
|
||||
// // dimensions.width, dimensions.height);
|
||||
|
||||
// await savePixelBufferToBmp(
|
||||
// pixelBuffer,
|
||||
// textureSize.width,
|
||||
// textureSize.height,
|
||||
// p.join(outDir.path, "unprojected_texture${i}.bmp"));
|
||||
|
||||
// pixels.add(pixelBuffer);
|
||||
|
||||
// if (i > 10) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// // }
|
||||
|
||||
// final aggregatePixelBuffer = medianImages(pixels);
|
||||
// await savePixelBufferToBmp(aggregatePixelBuffer, textureSize.width,
|
||||
// textureSize.height, "unproject_texture.bmp");
|
||||
// var pixelBufferPng = await pixelsToPng(
|
||||
// Uint8List.fromList(aggregatePixelBuffer),
|
||||
// dimensions.width,
|
||||
// dimensions.height);
|
||||
// File("${outDir.path}/unproject_texture.png")
|
||||
// .writeAsBytesSync(pixelBufferPng);
|
||||
|
||||
// await viewer.setPostProcessing(true);
|
||||
// await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
|
||||
// final unlit = await viewer.createUnlitMaterialInstance();
|
||||
// await viewer.removeEntity(cube);
|
||||
// cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
// materialInstance: unlit);
|
||||
// var reconstructedTexture = await viewer.createTexture(pixelBufferPng);
|
||||
// await viewer.applyTexture(reconstructedTexture, cube);
|
||||
|
||||
// await viewer.setCameraRotation(
|
||||
// Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) *
|
||||
// Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 6));
|
||||
// await testHelper.capture(viewer, "unproject_reconstruct");
|
||||
|
||||
// // now re-render
|
||||
// for (int i = 0; i < numFrames; i++) {
|
||||
// await viewer.setCameraPosition(-3 + (i / numFrames * 2), 4, 6);
|
||||
|
||||
// await viewer.setCameraRotation(
|
||||
// Quaternion.axisAngle(Vector3(0, 1, 0), -pi / 8) *
|
||||
// Quaternion.axisAngle(
|
||||
// Vector3(1, 0, 0), -pi / 6 - (i / numFrames * pi / 6)));
|
||||
|
||||
// var rendered = await testHelper.capture(viewer, "unproject_rerender$i");
|
||||
// var renderPng =
|
||||
// await pixelsToPng(rendered, dimensions.width, dimensions.height);
|
||||
|
||||
// File("${outDir.path}/unproject_rerender${i}.png")
|
||||
// .writeAsBytesSync(renderPng);
|
||||
// }
|
||||
// }, timeout: Timeout(Duration(minutes: 2)));
|
||||
// });
|
||||
}
|
||||
@@ -31,6 +31,29 @@ void main() async {
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('unlit fixed size material', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
|
||||
var materialInstance = await viewer.createUnlitFixedSizeMaterialInstance();
|
||||
var cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
|
||||
|
||||
await testHelper.capture(viewer, "unlit_fixed_size_default_scale");
|
||||
|
||||
await materialInstance.setParameterFloat("scale", 10.0);
|
||||
|
||||
await testHelper.capture(viewer, "unlit_fixed_size_scale_10");
|
||||
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('apply texture to custom ubershader material instance', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:async';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:test/test.dart';
|
||||
@@ -15,7 +17,6 @@ void main() async {
|
||||
expect(await view.getCamera(), isNotNull);
|
||||
|
||||
await viewer.dispose();
|
||||
|
||||
});
|
||||
|
||||
test('one swapchain, render view to render target', () async {
|
||||
@@ -37,7 +38,6 @@ void main() async {
|
||||
"default_swapchain_default_view_render_target");
|
||||
|
||||
await viewer.dispose();
|
||||
|
||||
});
|
||||
|
||||
test('create secondary view, default swapchain', () async {
|
||||
@@ -113,22 +113,29 @@ void main() async {
|
||||
|
||||
test('pick', () async {
|
||||
var viewer = await testHelper.createViewer(
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 5));
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 3));
|
||||
|
||||
final view = await viewer.getViewAt(0);
|
||||
|
||||
await view.setRenderable(true, testHelper.swapChain);
|
||||
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
await testHelper.capture(viewer, "view_pick");
|
||||
|
||||
final completer = Completer();
|
||||
late StreamSubscription listener;
|
||||
listener = viewer.pickResult.listen((result) async {
|
||||
completer.complete(result.entity);
|
||||
await listener.cancel();
|
||||
print("Pick result : ${result.fragX} ${result.fragY} ${result.fragZ}");
|
||||
});
|
||||
|
||||
viewer.pick(250, 250);
|
||||
await viewer.pick(250, 250);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
await viewer.requestFrame();
|
||||
await Future.delayed(Duration(milliseconds: 100));
|
||||
for (int i = 0; i < 3; i++) {
|
||||
await viewer.render();
|
||||
await Future.delayed(Duration(milliseconds: 16));
|
||||
}
|
||||
|
||||
expect(completer.isCompleted, true);
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'swift/swift_bindings.g.dart';
|
||||
import 'package:thermion_dart/src/utils/src/dart_resources.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
/// Test files are run in a variety of ways, find this package root in all.
|
||||
///
|
||||
/// Test files can be run from source from any working directory. The Dart SDK
|
||||
/// `tools/test.py` runs them from the root of the SDK for example.
|
||||
///
|
||||
/// Test files can be run from dill from the root of package. `package:test`
|
||||
/// does this.
|
||||
Uri findPackageRoot(String packageName) {
|
||||
final script = Platform.script;
|
||||
final fileName = script.name;
|
||||
|
||||
// We're likely running from source.
|
||||
var directory = script.resolve('.');
|
||||
while (true) {
|
||||
final dirName = directory.name;
|
||||
if (dirName == packageName) {
|
||||
return directory;
|
||||
}
|
||||
final parent = directory.resolve('..');
|
||||
if (parent == directory) break;
|
||||
directory = parent;
|
||||
}
|
||||
|
||||
throw StateError("Could not find package root for package '$packageName'. "
|
||||
'Tried finding the package root via Platform.script '
|
||||
"'${Platform.script.toFilePath()}' and Directory.current "
|
||||
"'${Directory.current.uri.toFilePath()}'.");
|
||||
}
|
||||
|
||||
extension on Uri {
|
||||
String get name => pathSegments.where((e) => e != '').last;
|
||||
}
|
||||
|
||||
late String testDir;
|
||||
void main() async {
|
||||
final packageUri = findPackageRoot('thermion_dart');
|
||||
testDir = Directory("${packageUri.toFilePath()}/test").path;
|
||||
final lib = ThermionTexture1(DynamicLibrary.open(
|
||||
'${packageUri.toFilePath()}/native/lib/macos/swift/libthermion_swift.dylib'));
|
||||
final object = ThermionTexture.new1(lib);
|
||||
object.initWithWidth_height_(500, 500);
|
||||
|
||||
final resourceLoader = calloc<ResourceLoaderWrapper>(1);
|
||||
var loadToOut = NativeCallable<
|
||||
Void Function(Pointer<Char>,
|
||||
Pointer<ResourceBuffer>)>.listener(DartResourceLoader.loadResource);
|
||||
|
||||
resourceLoader.ref.loadToOut = loadToOut.nativeFunction;
|
||||
var freeResource = NativeCallable<Void Function(ResourceBuffer)>.listener(
|
||||
DartResourceLoader.freeResource);
|
||||
resourceLoader.ref.freeResource = freeResource.nativeFunction;
|
||||
|
||||
var viewer = ThermionViewerFFI(resourceLoader: resourceLoader.cast<Void>());
|
||||
|
||||
await viewer.initialized;
|
||||
await viewer.createSwapChain(500, 500);
|
||||
await viewer.createRenderTarget(500, 500, object.metalTextureAddress);
|
||||
await viewer.updateViewportAndCameraProjection(500, 500);
|
||||
|
||||
group('viewport', () {
|
||||
test('viewport', () async {
|
||||
var entity = await viewer.createGeometry(GeometryHelper.cube());
|
||||
await viewer.setCameraPosition(0.0, 0.0, 4.0);
|
||||
await viewer.setCameraRotation(Quaternion.axisAngle(Vector3(0,0,1), pi/2));
|
||||
await viewer.queueRelativePositionUpdateWorldAxis(
|
||||
entity, 250.0, 250.0, 1, 0, 0);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
import 'dart:ffi';
|
||||
import 'dart:io';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'swift/swift_bindings.g.dart';
|
||||
import 'package:thermion_dart/src/utils/src/dart_resources.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart';
|
||||
|
||||
/// Test files are run in a variety of ways, find this package root in all.
|
||||
///
|
||||
/// Test files can be run from source from any working directory. The Dart SDK
|
||||
/// `tools/test.py` runs them from the root of the SDK for example.
|
||||
///
|
||||
/// Test files can be run from dill from the root of package. `package:test`
|
||||
/// does this.
|
||||
Uri findPackageRoot(String packageName) {
|
||||
final script = Platform.script;
|
||||
final fileName = script.name;
|
||||
|
||||
// We're likely running from source.
|
||||
var directory = script.resolve('.');
|
||||
while (true) {
|
||||
final dirName = directory.name;
|
||||
if (dirName == packageName) {
|
||||
return directory;
|
||||
}
|
||||
final parent = directory.resolve('..');
|
||||
if (parent == directory) break;
|
||||
directory = parent;
|
||||
}
|
||||
|
||||
throw StateError("Could not find package root for package '$packageName'. "
|
||||
'Tried finding the package root via Platform.script '
|
||||
"'${Platform.script.toFilePath()}' and Directory.current "
|
||||
"'${Directory.current.uri.toFilePath()}'.");
|
||||
}
|
||||
|
||||
extension on Uri {
|
||||
String get name => pathSegments.where((e) => e != '').last;
|
||||
}
|
||||
|
||||
late String testDir;
|
||||
void main() async {
|
||||
final packageUri = findPackageRoot('thermion_dart');
|
||||
testDir = Directory("${packageUri.toFilePath()}/test").path;
|
||||
final lib = ThermionTexture1(DynamicLibrary.open(
|
||||
'${packageUri.toFilePath()}/native/lib/macos/swift/libthermion_swift.dylib'));
|
||||
final object = ThermionTexture.new1(lib);
|
||||
object.initWithWidth_height_(500, 500);
|
||||
|
||||
final resourceLoader = calloc<ResourceLoaderWrapper>(1);
|
||||
var loadToOut = NativeCallable<
|
||||
Void Function(Pointer<Char>,
|
||||
Pointer<ResourceBuffer>)>.listener(DartResourceLoader.loadResource);
|
||||
|
||||
resourceLoader.ref.loadToOut = loadToOut.nativeFunction;
|
||||
var freeResource = NativeCallable<Void Function(ResourceBuffer)>.listener(
|
||||
DartResourceLoader.freeResource);
|
||||
resourceLoader.ref.freeResource = freeResource.nativeFunction;
|
||||
|
||||
var viewer = ThermionViewerFFI(resourceLoader: resourceLoader.cast<Void>());
|
||||
|
||||
await viewer.initialized;
|
||||
await viewer.createSwapChain(500, 500);
|
||||
await viewer.createRenderTarget(500, 500, object.metalTextureAddress);
|
||||
await viewer.updateViewportAndCameraProjection(500, 500);
|
||||
|
||||
|
||||
}
|
||||
@@ -1,3 +1,23 @@
|
||||
## 0.2.1-dev.16
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.15
|
||||
|
||||
- **FIX**: multiply coordinates by pixelRatio for scale events.
|
||||
|
||||
## 0.2.1-dev.14
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.13
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.12
|
||||
|
||||
- **FIX**: (flutter) (windows) remove deleted source file from Windows CMakeLists.
|
||||
|
||||
## 0.2.1-dev.11
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<p align="center">
|
||||
<a href="https://thermion.dev/quickstart">Quickstart (Flutter)</a> •
|
||||
<a href="https://thermion.dev/quickstart">Documentation</a> •
|
||||
<a href="https://thermion.dev/examples">Showcase</a> •
|
||||
<a href="https://thermion.dev/showcase">Showcase</a> •
|
||||
<a href="https://dartpad.thermion.dev/">Playground</a> •
|
||||
<a href="https://discord.gg/h2VdDK3EAQ">Discord</a>
|
||||
</p>
|
||||
|
||||
@@ -165,12 +165,12 @@ class _MobileListenerWidgetState extends State<_MobileListenerWidget> {
|
||||
},
|
||||
onScaleStart: (details) async {
|
||||
await widget.inputHandler.onScaleStart(
|
||||
details.localFocalPoint.toVector2(), details.pointerCount, details.sourceTimeStamp);
|
||||
details.localFocalPoint.toVector2() * widget.pixelRatio, details.pointerCount, details.sourceTimeStamp);
|
||||
},
|
||||
onScaleUpdate: (ScaleUpdateDetails details) async {
|
||||
await widget.inputHandler.onScaleUpdate(
|
||||
details.localFocalPoint.toVector2(),
|
||||
details.focalPointDelta.toVector2(),
|
||||
details.localFocalPoint.toVector2() * widget.pixelRatio,
|
||||
details.focalPointDelta.toVector2() * widget.pixelRatio,
|
||||
details.horizontalScale,
|
||||
details.verticalScale,
|
||||
details.scale,
|
||||
|
||||
@@ -68,12 +68,22 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
||||
var dpr = MediaQuery.of(context).devicePixelRatio;
|
||||
|
||||
var size = ((context.findRenderObject()) as RenderBox).size;
|
||||
|
||||
_logger.info(
|
||||
"Widget size in logical pixels ${size} (pixel ratio : $dpr)");
|
||||
|
||||
var width = (size.width * dpr).ceil();
|
||||
var height = (size.height * dpr).ceil();
|
||||
|
||||
_logger.info(
|
||||
"Target texture dimensions ${width}x${height} (pixel ratio : $dpr)");
|
||||
|
||||
_texture = await ThermionFlutterPlatform.instance
|
||||
.createTexture(widget.view, width, height);
|
||||
|
||||
_logger.info(
|
||||
"Actual texture dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
|
||||
|
||||
await widget.view.updateViewport(_texture!.width, _texture!.height);
|
||||
|
||||
try {
|
||||
@@ -177,6 +187,9 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
||||
var newWidth = newSize.width.ceil();
|
||||
var newHeight = newSize.height.ceil();
|
||||
|
||||
_logger.info(
|
||||
"Resizing texture to dimensions ${newWidth}x${newHeight} (pixel ratio : $dpr)");
|
||||
|
||||
await _texture?.resize(
|
||||
newWidth,
|
||||
newHeight,
|
||||
@@ -184,6 +197,9 @@ class _ThermionTextureWidgetState extends State<ThermionTextureWidget> {
|
||||
0,
|
||||
);
|
||||
|
||||
_logger.info(
|
||||
"Resized texture to dimensions ${_texture!.width}x${_texture!.height} (pixel ratio : $dpr)");
|
||||
|
||||
await widget.view.updateViewport(_texture!.width, _texture!.height);
|
||||
|
||||
await widget.onResize?.call(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: thermion_flutter
|
||||
description: Flutter plugin for 3D rendering with the Thermion toolkit.
|
||||
version: 0.2.1-dev.11
|
||||
version: 0.2.1-dev.16
|
||||
homepage: https://thermion.dev
|
||||
repository: https://github.com/nmfisher/thermion
|
||||
|
||||
@@ -17,10 +17,10 @@ dependencies:
|
||||
plugin_platform_interface: ^2.0.0
|
||||
ffi: ^2.1.2
|
||||
animation_tools_dart: ^0.1.0
|
||||
thermion_dart: ^0.2.1-dev.0.0.12
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.11
|
||||
thermion_flutter_ffi: ^0.2.1-dev.11
|
||||
thermion_flutter_web: ^0.2.0+2
|
||||
thermion_dart: ^0.2.1-dev.0.0.16
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.16
|
||||
thermion_flutter_ffi: ^0.2.1-dev.16
|
||||
thermion_flutter_web: ^0.2.0+7
|
||||
logging: ^1.2.0
|
||||
web: ^1.0.0
|
||||
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
## 0.2.1-dev.16
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.15
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.14
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.13
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.12
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.11
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: thermion_flutter_ffi
|
||||
description: An FFI implementation for thermion_flutter (i.e. all platforms except web).
|
||||
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
|
||||
version: 0.2.1-dev.11
|
||||
version: 0.2.1-dev.16
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
@@ -23,8 +23,8 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.1.0
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.11
|
||||
thermion_dart: ^0.2.1-dev.0.0.12
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.16
|
||||
thermion_dart: ^0.2.1-dev.0.0.16
|
||||
logging: ^1.2.0
|
||||
|
||||
dev_dependencies:
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
## 0.2.1-dev.16
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.15
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.14
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.13
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.12
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.1-dev.11
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: thermion_flutter_platform_interface
|
||||
description: A common platform interface for the thermion_flutter plugin.
|
||||
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
|
||||
version: 0.2.1-dev.11
|
||||
version: 0.2.1-dev.16
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
@@ -11,7 +11,7 @@ dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.1.0
|
||||
thermion_dart: ^0.2.1-dev.0.0.12
|
||||
thermion_dart: ^0.2.1-dev.0.0.16
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
## 0.2.0+7
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.0+6
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.0+5
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.0+4
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.0+3
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
## 0.2.0+2
|
||||
|
||||
- Update a dependency to the latest release.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: thermion_flutter_web
|
||||
description: A web platform interface for the thermion_flutter plugin.
|
||||
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
|
||||
version: 0.2.0+2
|
||||
version: 0.2.0+7
|
||||
|
||||
environment:
|
||||
sdk: ">=3.3.0 <4.0.0"
|
||||
@@ -20,8 +20,8 @@ dependencies:
|
||||
sdk: flutter
|
||||
plugin_platform_interface: ^2.1.0
|
||||
web: ^1.0.0
|
||||
thermion_dart: ^0.2.1-dev.0.0.12
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.11
|
||||
thermion_dart: ^0.2.1-dev.0.0.16
|
||||
thermion_flutter_platform_interface: ^0.2.1-dev.16
|
||||
flutter_web_plugins:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
Reference in New Issue
Block a user