Merge pull request #69 from nmfisher/feature/multiple_swapchains
Support multiple views/widgets/swapchains
This commit is contained in:
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -36,7 +36,7 @@ thermion_dart/native/lib/macos/debug/libmatlang.a filter=lfs diff=lfs merge=lfs
|
||||
thermion_dart/native/lib/macos/debug/libibl.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/debug/libmikktspace.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/libmatdbg_combined.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/swift/ThermionDartTexture.h filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/swift/ThermionTexture.h filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/debug/libfilamat_combined.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/debug/libfilament.a filter=lfs diff=lfs merge=lfs -text
|
||||
thermion_dart/native/lib/macos/libibl.a filter=lfs diff=lfs merge=lfs -text
|
||||
|
||||
357
CHANGELOG.md
357
CHANGELOG.md
@@ -1,5 +1,362 @@
|
||||
# Change Log
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 2024-10-10
|
||||
|
||||
### 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.6`](#thermion_dart---v021-dev006)
|
||||
- [`thermion_flutter_web` - `v0.1.0+7`](#thermion_flutter_web---v0107)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.5`](#thermion_flutter_platform_interface---v021-dev5)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.5`](#thermion_flutter---v021-dev5)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.5`](#thermion_flutter_ffi---v021-dev5)
|
||||
|
||||
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.1.0+7`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.5`
|
||||
- `thermion_flutter` - `v0.2.1-dev.5`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.5`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.6`
|
||||
|
||||
- Bump "thermion_dart" to `0.2.1-dev.0.0.6`.
|
||||
|
||||
|
||||
## 2024-10-10
|
||||
|
||||
### 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.5`](#thermion_dart---v021-dev005)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.4`](#thermion_flutter_platform_interface---v021-dev4)
|
||||
- [`thermion_flutter_web` - `v0.1.0+6`](#thermion_flutter_web---v0106)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.4`](#thermion_flutter---v021-dev4)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.4`](#thermion_flutter_ffi---v021-dev4)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.4`
|
||||
- `thermion_flutter_web` - `v0.1.0+6`
|
||||
- `thermion_flutter` - `v0.2.1-dev.4`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.4`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.5`
|
||||
|
||||
- Bump "thermion_dart" to `0.2.1-dev.0.0.5`.
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### 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.4`](#thermion_dart---v021-dev004)
|
||||
- [`thermion_flutter_web` - `v0.1.0+5`](#thermion_flutter_web---v0105)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.3`](#thermion_flutter---v021-dev3)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.3`](#thermion_flutter_platform_interface---v021-dev3)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.3`](#thermion_flutter_ffi---v021-dev3)
|
||||
|
||||
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.1.0+5`
|
||||
- `thermion_flutter` - `v0.2.1-dev.3`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.3`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.3`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.4`
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### 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.3`](#thermion_dart---v021-dev003)
|
||||
- [`thermion_flutter_web` - `v0.1.0+4`](#thermion_flutter_web---v0104)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.2`](#thermion_flutter---v021-dev2)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.2`](#thermion_flutter_platform_interface---v021-dev2)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.2`](#thermion_flutter_ffi---v021-dev2)
|
||||
|
||||
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.1.0+4`
|
||||
- `thermion_flutter` - `v0.2.1-dev.2`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.2`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.2`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.3`
|
||||
|
||||
- Bump "thermion_dart" to `0.2.1-dev.0.0.3`.
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### 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.2`](#thermion_dart---v021-dev002)
|
||||
- [`thermion_flutter_web` - `v0.1.0+3`](#thermion_flutter_web---v0103)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.1`](#thermion_flutter_ffi---v021-dev1)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.1`](#thermion_flutter---v021-dev1)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.1`](#thermion_flutter_platform_interface---v021-dev1)
|
||||
|
||||
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.1.0+3`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.1`
|
||||
- `thermion_flutter` - `v0.2.1-dev.1`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.1`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.2`
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### 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.1`](#thermion_dart---v021-dev001)
|
||||
- [`thermion_flutter_web` - `v0.1.0+2`](#thermion_flutter_web---v0102)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.0`](#thermion_flutter---v021-dev0)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.0`](#thermion_flutter_platform_interface---v021-dev0)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.0`](#thermion_flutter_ffi---v021-dev0)
|
||||
|
||||
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.1.0+2`
|
||||
- `thermion_flutter` - `v0.2.1-dev.0`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.1-dev.0`
|
||||
- `thermion_flutter_ffi` - `v0.2.1-dev.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.1`
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### 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.0`](#thermion_dart---v021-dev000)
|
||||
- [`thermion_flutter` - `v0.2.1-dev.0.0.0`](#thermion_flutter---v021-dev000)
|
||||
- [`thermion_flutter_ffi` - `v0.2.1-dev.0.0.0`](#thermion_flutter_ffi---v021-dev000)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.0.0.0`](#thermion_flutter_platform_interface---v021-dev000)
|
||||
- [`thermion_flutter_web` - `v0.1.0+1`](#thermion_flutter_web---v0101)
|
||||
|
||||
Packages with dependency updates only:
|
||||
|
||||
> Packages listed below depend on other packages in this workspace that have had changes. Their versions have been incremented to bump the minimum dependency versions of the packages they depend upon in this project.
|
||||
|
||||
- `thermion_flutter_web` - `v0.1.0+1`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.1-dev.0.0.0`
|
||||
|
||||
- y
|
||||
|
||||
#### `thermion_flutter` - `v0.2.1-dev.0.0.0`
|
||||
|
||||
- y
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.2.1-dev.0.0.0`
|
||||
|
||||
- y
|
||||
|
||||
#### `thermion_flutter_platform_interface` - `v0.2.1-dev.0.0.0`
|
||||
|
||||
- y
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- There are no breaking changes in this release.
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0`](#thermion_dart---v020)
|
||||
- [`thermion_flutter` - `v0.2.0`](#thermion_flutter---v020)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0`](#thermion_flutter_ffi---v020)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0`](#thermion_flutter_platform_interface---v020)
|
||||
- [`thermion_flutter_web` - `v0.1.0`](#thermion_flutter_web---v010)
|
||||
|
||||
Packages graduated to a stable release (see pre-releases prior to the stable version for changelog entries):
|
||||
|
||||
- `thermion_dart` - `v0.2.0`
|
||||
- `thermion_flutter` - `v0.2.0`
|
||||
- `thermion_flutter_ffi` - `v0.2.0`
|
||||
- `thermion_flutter_platform_interface` - `v0.2.0`
|
||||
- `thermion_flutter_web` - `v0.1.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0`
|
||||
|
||||
#### `thermion_flutter` - `v0.2.0`
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.2.0`
|
||||
|
||||
#### `thermion_flutter_platform_interface` - `v0.2.0`
|
||||
|
||||
#### `thermion_flutter_web` - `v0.1.0`
|
||||
|
||||
|
||||
## 2024-10-02
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`thermion_dart` - `v0.2.0-dev.8.0.0`](#thermion_dart---v020-dev800)
|
||||
- [`thermion_flutter_ffi` - `v0.2.0-dev.8.0.0`](#thermion_flutter_ffi---v020-dev800)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`thermion_flutter` - `v0.2.0-dev.8.0.0`](#thermion_flutter---v020-dev800)
|
||||
- [`thermion_flutter_platform_interface` - `v0.2.0-dev.8.0.0`](#thermion_flutter_platform_interface---v020-dev800)
|
||||
- [`thermion_flutter_web` - `v0.1.0-dev.8.0.0`](#thermion_flutter_web---v010-dev800)
|
||||
|
||||
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.1.0-dev.8.0.0`
|
||||
|
||||
---
|
||||
|
||||
#### `thermion_dart` - `v0.2.0-dev.8.0.0`
|
||||
|
||||
- **REFACTOR**: continual refactor to support multiple render targets.
|
||||
- **FEAT**: camera and resizing improvements.
|
||||
- **FEAT**: support multiple ThermionWidget on Android.
|
||||
- **FEAT**: use imported texture on iOS.
|
||||
- **FEAT**: working implementation of multiple widgets on macos.
|
||||
- **FEAT**: more work on multiple views/swapchains.
|
||||
- **FEAT**: add setParameterFloat2 method.
|
||||
- **FEAT**: add setParameterFloat2 method.
|
||||
- **FEAT**: add uvScale to unlit material.
|
||||
- **FEAT**: add ThirdPersonCameraDelegate.
|
||||
- **FEAT**: set camera model matrix directly.
|
||||
- **FEAT**: expose more camera methods.
|
||||
- **BREAKING** **REFACTOR**: refactor to support multiple Views/Render Targets.
|
||||
- **BREAKING** **REFACTOR**: remove RenderThread methods no longer needed.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FEAT**: big refactor to support multiple swapchains.
|
||||
- **BREAKING** **FEAT**: set baseColorIndex to -1 by default in unlit materialss.
|
||||
|
||||
#### `thermion_flutter_ffi` - `v0.2.0-dev.8.0.0`
|
||||
|
||||
- **REFACTOR**: continual refactor to support multiple render targets.
|
||||
- **FEAT**: support multiple ThermionWidget on Android.
|
||||
- **FEAT**: use imported texture on iOS.
|
||||
- **FEAT**: working implementation of multiple widgets on macos.
|
||||
- **BREAKING** **REFACTOR**: refactor to support multiple Views/Render Targets.
|
||||
- **BREAKING** **FEAT**: big refactor to support multiple swapchains.
|
||||
|
||||
#### `thermion_flutter` - `v0.2.0-dev.8.0.0`
|
||||
|
||||
- **REFACTOR**: continual refactor to support multiple render targets.
|
||||
- **FEAT**: camera and resizing improvements.
|
||||
- **FEAT**: support multiple ThermionWidget on Android.
|
||||
- **FEAT**: use imported texture on iOS.
|
||||
- **FEAT**: working implementation of multiple widgets on macos.
|
||||
- **FEAT**: add rendering check to ThermionWidget ticker.
|
||||
|
||||
#### `thermion_flutter_platform_interface` - `v0.2.0-dev.8.0.0`
|
||||
|
||||
- **REFACTOR**: continual refactor to support multiple render targets.
|
||||
- **FEAT**: support multiple ThermionWidget on Android.
|
||||
- **FEAT**: working implementation of multiple widgets on macos.
|
||||
|
||||
# Change Log
|
||||
|
||||
v0.2.0
|
||||
|
||||
- **BREAKING** Dart SDK 3.6.0 required
|
||||
|
||||
1
Makefile
1
Makefile
@@ -12,6 +12,7 @@ flutter-example-web: dart-web-clean dart-web
|
||||
flutter-example-macos:
|
||||
cd thermion_flutter_federated/thermion_flutter/example/web && flutter run -d macos
|
||||
swift-bindings:
|
||||
swiftc -c thermion_flutter/thermion_flutter/macos/Classes/ThermionTexture.swift -module-name swift_module -emit-objc-header-path thermion_dart/native/include/generated/ThermionTextureSwiftObjCAPI.h -emit-library -o thermion_dart/test/libThermionTextureSwift.dylib
|
||||
cd thermion_dart/ && dart --enable-experiment=native-assets run ffigen --config ffigen/swift.yaml
|
||||
bindings:
|
||||
cd thermion_dart/ && dart --enable-experiment=native-assets run ffigen --config ffigen/native.yaml
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
## Android
|
||||
|
||||
### Min SDK version
|
||||
|
||||
Thermion requires Android SDK version 22, so change your `app/android/build.gradle` to match this version or higher:
|
||||
|
||||
```groovy
|
||||
defaultConfig {
|
||||
...
|
||||
minSdk = 22
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### Shrink/Minify Resources
|
||||
|
||||
In release mode, you must add the following to your `app/build.gradle`:
|
||||
|
||||
```
|
||||
|
||||
@@ -1,3 +1,54 @@
|
||||
## 0.2.1-dev.0.0.6
|
||||
|
||||
- Bump "thermion_dart" to `0.2.1-dev.0.0.6`.
|
||||
|
||||
## 0.2.1-dev.0.0.5
|
||||
|
||||
- Bump "thermion_dart" to `0.2.1-dev.0.0.5`.
|
||||
|
||||
## 0.2.1-dev.0.0.4
|
||||
|
||||
## 0.2.1-dev.0.0.3
|
||||
|
||||
- Bump "thermion_dart" to `0.2.1-dev.0.0.3`.
|
||||
|
||||
## 0.2.1-dev.0.0.2
|
||||
|
||||
## 0.2.1-dev.0.0.1
|
||||
|
||||
## 0.2.1-dev.0.0.0
|
||||
|
||||
- y
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- Graduate package to a stable release. See pre-releases prior to this version for changelog entries.
|
||||
|
||||
## 0.2.0-dev.8.0.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **REFACTOR**: continual refactor to support multiple render targets.
|
||||
- **FEAT**: camera and resizing improvements.
|
||||
- **FEAT**: support multiple ThermionWidget on Android.
|
||||
- **FEAT**: use imported texture on iOS.
|
||||
- **FEAT**: working implementation of multiple widgets on macos.
|
||||
- **FEAT**: more work on multiple views/swapchains.
|
||||
- **FEAT**: add setParameterFloat2 method.
|
||||
- **FEAT**: add setParameterFloat2 method.
|
||||
- **FEAT**: add uvScale to unlit material.
|
||||
- **FEAT**: add ThirdPersonCameraDelegate.
|
||||
- **FEAT**: set camera model matrix directly.
|
||||
- **FEAT**: expose more camera methods.
|
||||
- **BREAKING** **REFACTOR**: refactor to support multiple Views/Render Targets.
|
||||
- **BREAKING** **REFACTOR**: remove RenderThread methods no longer needed.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FIX**: replace queuePosition/Rotation with queueTransforms.
|
||||
- **BREAKING** **FEAT**: big refactor to support multiple swapchains.
|
||||
- **BREAKING** **FEAT**: set baseColorIndex to -1 by default in unlit materialss.
|
||||
|
||||
## 0.2.0-dev.7.0
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
30
thermion_dart/extras/windows/CMakeLists.txt
Normal file
30
thermion_dart/extras/windows/CMakeLists.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
set(PROJECT_NAME "thermion_windows")
|
||||
project(${PROJECT_NAME} LANGUAGES C CXX)
|
||||
|
||||
cmake_policy(VERSION 3.14...3.25)
|
||||
|
||||
add_compile_definitions(WGL_USE_BACKING_WINDOW)
|
||||
add_compile_definitions(UNICODE)
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED
|
||||
"thermion_window.cpp"
|
||||
)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
|
||||
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
|
||||
target_include_directories(${PROJECT_NAME} INTERFACE
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/include"
|
||||
"${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/include/filament"
|
||||
"${CMAKE_SOURCE_DIR}/../../../../thermion_dart/native/include"
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/include
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
Shlwapi
|
||||
opengl32
|
||||
dwmapi
|
||||
comctl32
|
||||
)
|
||||
|
||||
244
thermion_dart/extras/windows/thermion_window.cpp
Normal file
244
thermion_dart/extras/windows/thermion_window.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
#include "thermion_window.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include <Windows.h>
|
||||
#include <dwmapi.h>
|
||||
#include <ShObjIdl.h>
|
||||
|
||||
#pragma comment(lib, "dwmapi.lib")
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
|
||||
namespace thermion {
|
||||
|
||||
static constexpr auto kClassName = L"THERMION_WINDOW";
|
||||
static constexpr auto kWindowName = L"thermion_window";
|
||||
static bool was_window_hidden_due_to_minimize_ = false;
|
||||
static WPARAM last_wm_size_wparam_ = SIZE_RESTORED;
|
||||
uint64_t last_thread_time_ = 0;
|
||||
static constexpr auto kNativeViewPositionAndShowDelay = 300;
|
||||
|
||||
typedef enum _WINDOWCOMPOSITIONATTRIB {
|
||||
WCA_UNDEFINED = 0,
|
||||
WCA_NCRENDERING_ENABLED = 1,
|
||||
WCA_NCRENDERING_POLICY = 2,
|
||||
WCA_TRANSITIONS_FORCEDISABLED = 3,
|
||||
WCA_ALLOW_NCPAINT = 4,
|
||||
WCA_CAPTION_BUTTON_BOUNDS = 5,
|
||||
WCA_NONCLIENT_RTL_LAYOUT = 6,
|
||||
WCA_FORCE_ICONIC_REPRESENTATION = 7,
|
||||
WCA_EXTENDED_FRAME_BOUNDS = 8,
|
||||
WCA_HAS_ICONIC_BITMAP = 9,
|
||||
WCA_THEME_ATTRIBUTES = 10,
|
||||
WCA_NCRENDERING_EXILED = 11,
|
||||
WCA_NCADORNMENTINFO = 12,
|
||||
WCA_EXCLUDED_FROM_LIVEPREVIEW = 13,
|
||||
WCA_VIDEO_OVERLAY_ACTIVE = 14,
|
||||
WCA_FORCE_ACTIVEWINDOW_APPEARANCE = 15,
|
||||
WCA_DISALLOW_PEEK = 16,
|
||||
WCA_CLOAK = 17,
|
||||
WCA_CLOAKED = 18,
|
||||
WCA_ACCENT_POLICY = 19,
|
||||
WCA_FREEZE_REPRESENTATION = 20,
|
||||
WCA_EVER_UNCLOAKED = 21,
|
||||
WCA_VISUAL_OWNER = 22,
|
||||
WCA_HOLOGRAPHIC = 23,
|
||||
WCA_EXCLUDED_FROM_DDA = 24,
|
||||
WCA_PASSIVEUPDATEMODE = 25,
|
||||
WCA_USEDARKMODECOLORS = 26,
|
||||
WCA_LAST = 27
|
||||
} WINDOWCOMPOSITIONATTRIB;
|
||||
|
||||
typedef struct _WINDOWCOMPOSITIONATTRIBDATA {
|
||||
WINDOWCOMPOSITIONATTRIB Attrib;
|
||||
PVOID pvData;
|
||||
SIZE_T cbData;
|
||||
} WINDOWCOMPOSITIONATTRIBDATA;
|
||||
|
||||
typedef enum _ACCENT_STATE {
|
||||
ACCENT_DISABLED = 0,
|
||||
ACCENT_ENABLE_GRADIENT = 1,
|
||||
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
|
||||
ACCENT_ENABLE_BLURBEHIND = 3,
|
||||
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
|
||||
ACCENT_ENABLE_HOSTBACKDROP = 5,
|
||||
ACCENT_INVALID_STATE = 6
|
||||
} ACCENT_STATE;
|
||||
|
||||
typedef struct _ACCENT_POLICY {
|
||||
ACCENT_STATE AccentState;
|
||||
DWORD AccentFlags;
|
||||
DWORD GradientColor;
|
||||
DWORD AnimationId;
|
||||
} ACCENT_POLICY;
|
||||
|
||||
typedef BOOL(WINAPI* _GetWindowCompositionAttribute)(
|
||||
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||
typedef BOOL(WINAPI* _SetWindowCompositionAttribute)(
|
||||
HWND, WINDOWCOMPOSITIONATTRIBDATA*);
|
||||
|
||||
static _SetWindowCompositionAttribute g_set_window_composition_attribute = NULL;
|
||||
static bool g_set_window_composition_attribute_initialized = false;
|
||||
|
||||
typedef LONG NTSTATUS, *PNTSTATUS;
|
||||
#define STATUS_SUCCESS (0x00000000)
|
||||
|
||||
typedef NTSTATUS(WINAPI* RtlGetVersionPtr)(PRTL_OSVERSIONINFOW);
|
||||
|
||||
RTL_OSVERSIONINFOW GetWindowsVersion() {
|
||||
HMODULE hmodule = ::GetModuleHandleW(L"ntdll.dll");
|
||||
if (hmodule) {
|
||||
RtlGetVersionPtr rtl_get_version_ptr =
|
||||
(RtlGetVersionPtr)::GetProcAddress(hmodule, "RtlGetVersion");
|
||||
if (rtl_get_version_ptr != nullptr) {
|
||||
RTL_OSVERSIONINFOW rovi = {0};
|
||||
rovi.dwOSVersionInfoSize = sizeof(rovi);
|
||||
if (STATUS_SUCCESS == rtl_get_version_ptr(&rovi)) {
|
||||
return rovi;
|
||||
}
|
||||
}
|
||||
}
|
||||
RTL_OSVERSIONINFOW rovi = {0};
|
||||
return rovi;
|
||||
}
|
||||
|
||||
void SetWindowComposition(HWND window, int32_t accent_state,
|
||||
int32_t gradient_color) {
|
||||
// TODO: Look for a better available API.
|
||||
if (GetWindowsVersion().dwBuildNumber >= 18362) {
|
||||
if (!g_set_window_composition_attribute_initialized) {
|
||||
auto user32 = ::GetModuleHandleA("user32.dll");
|
||||
if (user32) {
|
||||
g_set_window_composition_attribute =
|
||||
reinterpret_cast<_SetWindowCompositionAttribute>(
|
||||
::GetProcAddress(user32, "SetWindowCompositionAttribute"));
|
||||
if (g_set_window_composition_attribute) {
|
||||
g_set_window_composition_attribute_initialized = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
ACCENT_POLICY accent = {static_cast<ACCENT_STATE>(accent_state), 2,
|
||||
static_cast<DWORD>(gradient_color), 0};
|
||||
WINDOWCOMPOSITIONATTRIBDATA data;
|
||||
data.Attrib = WCA_ACCENT_POLICY;
|
||||
data.pvData = &accent;
|
||||
data.cbData = sizeof(accent);
|
||||
g_set_window_composition_attribute(window, &data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
|
||||
WPARAM const wparam,
|
||||
LPARAM const lparam) noexcept {
|
||||
switch (message) {
|
||||
std::cout << message <<std::endl;
|
||||
case WM_MOUSEMOVE: {
|
||||
TRACKMOUSEEVENT event;
|
||||
event.cbSize = sizeof(event);
|
||||
event.hwndTrack = window;
|
||||
event.dwFlags = TME_HOVER;
|
||||
event.dwHoverTime = 200;
|
||||
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
|
||||
if (user_data) {
|
||||
HWND flutterRootWindow = reinterpret_cast<HWND>(user_data);
|
||||
::SetForegroundWindow(flutterRootWindow);
|
||||
LONG ex_style = ::GetWindowLong(flutterRootWindow, GWL_EXSTYLE);
|
||||
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
|
||||
::SetWindowLong(flutterRootWindow, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_ERASEBKGND: {
|
||||
HDC hdc = (HDC)wparam;
|
||||
RECT rect;
|
||||
GetClientRect(window, &rect);
|
||||
|
||||
// Get the ThermionWindow instance associated with this window
|
||||
ThermionWindow* thermionWindow = reinterpret_cast<ThermionWindow*>(
|
||||
GetWindowLongPtr(window, GWLP_USERDATA));
|
||||
|
||||
if (thermionWindow) {
|
||||
HBRUSH brush = CreateSolidBrush(RGB(0, 0, 255));
|
||||
FillRect(hdc, &rect, brush);
|
||||
DeleteObject(brush);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_SIZE:
|
||||
break;
|
||||
case WM_MOVE:
|
||||
case WM_MOVING:
|
||||
case WM_ACTIVATE:
|
||||
case WM_WINDOWPOSCHANGED: {
|
||||
// NativeViewCore::GetInstance()->SetHitTestBehavior(0);
|
||||
auto user_data = ::GetWindowLongPtr(window, GWLP_USERDATA);
|
||||
if (user_data) {
|
||||
HWND flutterRootWindow = reinterpret_cast<HWND>(user_data);
|
||||
::SetForegroundWindow(flutterRootWindow);
|
||||
// NativeViewCore::GetInstance()->SetHitTestBehavior(0);
|
||||
LONG ex_style = ::GetWindowLong(flutterRootWindow, GWL_EXSTYLE);
|
||||
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
|
||||
::SetWindowLong(flutterRootWindow, GWL_EXSTYLE, ex_style);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ::DefWindowProc(window, message, wparam, lparam);
|
||||
}
|
||||
|
||||
ThermionWindow::ThermionWindow(int width,
|
||||
int height,
|
||||
int left,
|
||||
int top) : _width(width), _height(height), _left(left), _top(top) {
|
||||
// create the HWND for Filament
|
||||
auto window_class = WNDCLASSEX{};
|
||||
::SecureZeroMemory(&window_class, sizeof(window_class));
|
||||
window_class.cbSize = sizeof(window_class);
|
||||
window_class.style = CS_HREDRAW | CS_VREDRAW;
|
||||
window_class.lpfnWndProc = FilamentWindowProc;
|
||||
window_class.hInstance = 0;
|
||||
window_class.lpszClassName = kClassName;
|
||||
window_class.hCursor = ::LoadCursorW(nullptr, IDC_ARROW);
|
||||
window_class.hbrBackground = ::CreateSolidBrush(RGB(0,255,0));
|
||||
::RegisterClassExW(&window_class);
|
||||
_windowHandle = ::CreateWindow(kClassName, kWindowName, WS_OVERLAPPEDWINDOW,
|
||||
0, 0, _width, _height, nullptr,
|
||||
nullptr, GetModuleHandle(nullptr), nullptr);
|
||||
|
||||
// Disable DWM animations
|
||||
auto disable_window_transitions = TRUE;
|
||||
DwmSetWindowAttribute(_windowHandle, DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||
&disable_window_transitions,
|
||||
sizeof(disable_window_transitions));
|
||||
|
||||
auto style = ::GetWindowLong(_windowHandle, GWL_STYLE);
|
||||
style &= ~(WS_CAPTION | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX |
|
||||
WS_EX_APPWINDOW);
|
||||
::SetWindowLong(_windowHandle, GWL_STYLE, style);
|
||||
|
||||
// // remove taskbar entry for the window we created
|
||||
// ITaskbarList3* taskbar = nullptr;
|
||||
// ::CoCreateInstance(CLSID_TaskbarList, 0, CLSCTX_INPROC_SERVER,
|
||||
// IID_PPV_ARGS(&taskbar));
|
||||
// taskbar->DeleteTab(_windowHandle);
|
||||
// taskbar->Release();
|
||||
::ShowWindow(_windowHandle, SW_SHOW);
|
||||
UpdateWindow(_windowHandle);
|
||||
}
|
||||
|
||||
void ThermionWindow::Resize(int width, int height, int left, int top) {
|
||||
_width = width;
|
||||
_height = height;
|
||||
_left = left;
|
||||
_top = top;
|
||||
}
|
||||
|
||||
HWND ThermionWindow::GetHandle() { return _windowHandle; }
|
||||
} // namespace thermion_flutter
|
||||
57
thermion_dart/extras/windows/thermion_window.h
Normal file
57
thermion_dart/extras/windows/thermion_window.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifdef IS_DLL
|
||||
#define EMSCRIPTEN_KEEPALIVE __declspec(dllimport)
|
||||
#else
|
||||
#define EMSCRIPTEN_KEEPALIVE __declspec(dllexport)
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <Windows.h>
|
||||
|
||||
namespace thermion {
|
||||
|
||||
///
|
||||
/// Instantiating a ThermionWindow creates a HWND that can be passed
|
||||
/// to Filament to create a swapchain.
|
||||
///
|
||||
///
|
||||
class ThermionWindow {
|
||||
public:
|
||||
ThermionWindow(
|
||||
int width,
|
||||
int height,
|
||||
int left,
|
||||
int top);
|
||||
HWND GetHandle();
|
||||
void Resize(int width, int height, int left, int top);
|
||||
private:
|
||||
HWND _windowHandle;
|
||||
uint32_t _width = 0;
|
||||
uint32_t _height = 0;
|
||||
uint32_t _left = 0;
|
||||
uint32_t _top = 0;
|
||||
};
|
||||
|
||||
static ThermionWindow* _window;
|
||||
|
||||
extern "C" {
|
||||
EMSCRIPTEN_KEEPALIVE intptr_t create_thermion_window(int width, int height, int left, int top) {
|
||||
_window = new ThermionWindow(width, height, left, top);
|
||||
return (intptr_t)_window->GetHandle();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void update() {
|
||||
MSG msg;
|
||||
if(GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -3,10 +3,16 @@ headers:
|
||||
entry-points:
|
||||
- '../native/include/ThermionDartRenderThreadApi.h'
|
||||
- '../native/include/ThermionDartApi.h'
|
||||
- '../native/include/TView.h'
|
||||
- '../native/include/TCamera.h'
|
||||
- '../native/include/TGizmo.h'
|
||||
- '../native/include/ResourceBuffer.h'
|
||||
include-directives:
|
||||
- '../native/include/ThermionDartRenderThreadApi.h'
|
||||
- '../native/include/ThermionDartApi.h'
|
||||
- '../native/include/TView.h'
|
||||
- '../native/include/TCamera.h'
|
||||
- '../native/include/TGizmo.h'
|
||||
- '../native/include/ResourceBuffer.h'
|
||||
- '../native/include/APIBoundaryTypes.h'
|
||||
ffi-native:
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
name: ThermionDartTexture
|
||||
description: Bindings for ThermionDartTexture.
|
||||
name: ThermionTextureSwift
|
||||
description: Bindings for ThermionTexture.
|
||||
language: objc
|
||||
output: 'lib/thermion_dart/swift/swift_bindings.g.dart'
|
||||
output: '../lib/src/swift/swift_bindings.g.dart'
|
||||
exclude-all-by-default: true
|
||||
objc-interfaces:
|
||||
include:
|
||||
- 'ThermionDartTexture'
|
||||
- 'ThermionTextureSwift'
|
||||
module:
|
||||
'ThermionDartTexture': 'thermion_dart_texture'
|
||||
'ThermionTextureSwift': 'swift_module'
|
||||
headers:
|
||||
entry-points:
|
||||
- 'native/lib/macos/swift/ThermionDartTexture.h'
|
||||
- '../native/include/generated/ThermionTextureSwiftObjCAPI.h'
|
||||
preamble: |
|
||||
// ignore_for_file: camel_case_types, non_constant_identifier_names, unused_element, unused_field, return_of_invalid_type, void_checks, annotate_overrides, no_leading_underscores_for_local_identifiers, library_private_types_in_public_apia
|
||||
@@ -32,19 +32,14 @@ void main(List<String> args) async {
|
||||
final name = "thermion_dart.dart";
|
||||
final libUri = config.outputDirectory
|
||||
.resolve(config.targetOS.libraryFileName(name, linkMode));
|
||||
output.addAssets(
|
||||
[
|
||||
NativeCodeAsset(
|
||||
package: config.packageName,
|
||||
name: name,
|
||||
file: libUri,
|
||||
linkMode: linkMode,
|
||||
os: config.targetOS,
|
||||
architecture: config.dryRun ? null : config.targetArchitecture,
|
||||
)
|
||||
],
|
||||
linkInPackage: null,
|
||||
);
|
||||
output.addAsset(NativeCodeAsset(
|
||||
package: config.packageName,
|
||||
name: name,
|
||||
file: libUri,
|
||||
linkMode: linkMode,
|
||||
os: config.targetOS,
|
||||
architecture: config.dryRun ? null : config.targetArchitecture,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -58,7 +53,7 @@ void main(List<String> args) async {
|
||||
.map((f) => f.path)
|
||||
.toList();
|
||||
sources.addAll([
|
||||
"${config.packageRoot.toFilePath()}/native/include/material/gizmo.c",
|
||||
"${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",
|
||||
@@ -92,7 +87,6 @@ void main(List<String> args) async {
|
||||
"basis_transcoder"
|
||||
];
|
||||
|
||||
|
||||
if (platform == "windows") {
|
||||
libDir = Directory(libDir).uri.toFilePath();
|
||||
libs = libs.map((lib) => "${libDir}${lib}.lib").toList();
|
||||
@@ -118,7 +112,12 @@ void main(List<String> args) async {
|
||||
defines["WIN32"] = "1";
|
||||
defines["_DEBUG"] = "1";
|
||||
defines["_DLL"] = "1";
|
||||
flags.addAll(["/std:c++20", "/MDd"]);
|
||||
flags.addAll([
|
||||
"/std:c++20",
|
||||
"/MDd",
|
||||
"/VERBOSE",
|
||||
...defines.keys.map((k) => "/D$k=${defines[k]}").toList()
|
||||
]);
|
||||
}
|
||||
|
||||
if (platform == "ios") {
|
||||
@@ -149,16 +148,26 @@ void main(List<String> args) async {
|
||||
name: packageName,
|
||||
language: Language.cpp,
|
||||
assetName: 'thermion_dart.dart',
|
||||
sources: sources,
|
||||
includes: ['native/include', 'native/include/filament'],
|
||||
defines: defines,
|
||||
sources: platform == "windows" ? [] : sources,
|
||||
includes: platform == "windows"
|
||||
? []
|
||||
: ['native/include', 'native/include/filament'],
|
||||
defines: platform == "windows" ? {} : defines,
|
||||
flags: [
|
||||
if (platform == "macos") '-mmacosx-version-min=13.0',
|
||||
if (platform == "ios") '-mios-version-min=13.0',
|
||||
...flags,
|
||||
...frameworks,
|
||||
...libs.map((lib) => "-l$lib"),
|
||||
"-L$libDir",
|
||||
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",
|
||||
...sources,
|
||||
'/link',
|
||||
"/LIBPATH:$libDir",
|
||||
'/DLL',
|
||||
]
|
||||
],
|
||||
dartBuildFiles: ['hook/build.dart'],
|
||||
);
|
||||
@@ -177,17 +186,24 @@ void main(List<String> args) async {
|
||||
Architecture.ia32 => "i686-linux-android",
|
||||
_ => throw FormatException('Invalid')
|
||||
};
|
||||
|
||||
|
||||
var compilerPath = config.cCompiler.compiler!.path;
|
||||
|
||||
if(Platform.isWindows && compilerPath.startsWith("/")) {
|
||||
|
||||
if (Platform.isWindows && compilerPath.startsWith("/")) {
|
||||
compilerPath = compilerPath.substring(1);
|
||||
}
|
||||
|
||||
var ndkRoot = File(compilerPath).parent.parent.uri.toFilePath(windows:true);
|
||||
|
||||
var stlPath =
|
||||
File([ndkRoot, "sysroot", "usr", "lib", archExtension, "libc++_shared.so"].join(Platform.pathSeparator));
|
||||
var ndkRoot =
|
||||
File(compilerPath).parent.parent.uri.toFilePath(windows: true);
|
||||
|
||||
var stlPath = File([
|
||||
ndkRoot,
|
||||
"sysroot",
|
||||
"usr",
|
||||
"lib",
|
||||
archExtension,
|
||||
"libc++_shared.so"
|
||||
].join(Platform.pathSeparator));
|
||||
output.addAsset(NativeCodeAsset(
|
||||
package: "thermion_dart",
|
||||
name: "libc++_shared.so",
|
||||
@@ -201,7 +217,7 @@ void main(List<String> args) async {
|
||||
if (config.targetOS == "windows") {
|
||||
output.addAsset(
|
||||
NativeCodeAsset(
|
||||
package: "thermion_dart",
|
||||
package: config.packageName,
|
||||
name: "thermion_dart.dll",
|
||||
linkMode: DynamicLoadingBundled(),
|
||||
os: config.targetOS,
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../../thermion_dart.dart';
|
||||
|
||||
abstract class AbstractGizmo {
|
||||
|
||||
bool get isVisible;
|
||||
bool get isHovered;
|
||||
|
||||
Future translate(double transX, double transY);
|
||||
|
||||
void reset();
|
||||
|
||||
Future attach(ThermionEntity entity);
|
||||
|
||||
Future detach();
|
||||
|
||||
Stream<Aabb2> get boundingBox;
|
||||
|
||||
void checkHover(double x, double y);
|
||||
}
|
||||
@@ -3,4 +3,5 @@ library;
|
||||
export 'src/input_handler.dart';
|
||||
export 'src/delegates.dart';
|
||||
export 'src/delegate_gesture_handler.dart';
|
||||
export 'src/implementations/default_pick_delegate.dart';
|
||||
export 'src/implementations/third_person_camera_delegate.dart';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
@@ -9,6 +10,12 @@ import 'implementations/free_flight_camera_delegate.dart';
|
||||
class DelegateInputHandler implements InputHandler {
|
||||
final ThermionViewer viewer;
|
||||
|
||||
Stream<List<InputType>> get gestures => _gesturesController.stream;
|
||||
final _gesturesController = StreamController<List<InputType>>.broadcast();
|
||||
|
||||
Stream get cameraUpdated => _cameraUpdatedController.stream;
|
||||
final _cameraUpdatedController = StreamController.broadcast();
|
||||
|
||||
final _logger = Logger("DelegateInputHandler");
|
||||
|
||||
InputHandlerDelegate? transformDelegate;
|
||||
@@ -20,6 +27,8 @@ class DelegateInputHandler implements InputHandler {
|
||||
|
||||
Map<InputType, InputAction> _actions = {
|
||||
InputType.LMB_HOLD_AND_MOVE: InputAction.TRANSLATE,
|
||||
InputType.SCALE1: InputAction.TRANSLATE,
|
||||
InputType.SCALE2: InputAction.ZOOM,
|
||||
InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE,
|
||||
InputType.SCROLLWHEEL: InputAction.TRANSLATE,
|
||||
InputType.POINTER_MOVE: InputAction.NONE,
|
||||
@@ -54,7 +63,7 @@ class DelegateInputHandler implements InputHandler {
|
||||
|
||||
factory DelegateInputHandler.fixedOrbit(ThermionViewer viewer,
|
||||
{double minimumDistance = 10.0,
|
||||
double? Function(Vector3)? getDistanceToTarget,
|
||||
Future<double?> Function(Vector3)? getDistanceToTarget,
|
||||
ThermionEntity? entity,
|
||||
PickDelegate? pickDelegate}) =>
|
||||
DelegateInputHandler(
|
||||
@@ -69,11 +78,22 @@ class DelegateInputHandler implements InputHandler {
|
||||
});
|
||||
|
||||
factory DelegateInputHandler.flight(ThermionViewer viewer,
|
||||
{PickDelegate? pickDelegate, bool freeLook=false, double? clampY, ThermionEntity? entity}) =>
|
||||
{PickDelegate? pickDelegate,
|
||||
bool freeLook = false,
|
||||
double panSensitivity = 0.1,
|
||||
double movementSensitivity = 0.1,
|
||||
double rotateSensitivity = 0.01,
|
||||
double? clampY,
|
||||
ThermionEntity? entity}) =>
|
||||
DelegateInputHandler(
|
||||
viewer: viewer,
|
||||
pickDelegate: pickDelegate,
|
||||
transformDelegate: FreeFlightInputHandlerDelegate(viewer, clampY:clampY, entity:entity),
|
||||
transformDelegate: FreeFlightInputHandlerDelegate(viewer,
|
||||
clampY: clampY,
|
||||
entity: entity,
|
||||
rotationSensitivity: rotateSensitivity,
|
||||
panSensitivity: panSensitivity,
|
||||
movementSensitivity: movementSensitivity),
|
||||
actions: {
|
||||
InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE,
|
||||
InputType.SCROLLWHEEL: InputAction.TRANSLATE,
|
||||
@@ -82,8 +102,9 @@ class DelegateInputHandler implements InputHandler {
|
||||
InputType.KEYDOWN_W: InputAction.TRANSLATE,
|
||||
InputType.KEYDOWN_S: InputAction.TRANSLATE,
|
||||
InputType.KEYDOWN_D: InputAction.TRANSLATE,
|
||||
if(freeLook)
|
||||
InputType.POINTER_MOVE: InputAction.ROTATE,
|
||||
InputType.SCALE1: InputAction.TRANSLATE,
|
||||
InputType.SCALE2: InputAction.ZOOM,
|
||||
if (freeLook) InputType.POINTER_MOVE: InputAction.ROTATE,
|
||||
});
|
||||
|
||||
bool _processing = false;
|
||||
@@ -102,39 +123,53 @@ class DelegateInputHandler implements InputHandler {
|
||||
|
||||
await transformDelegate?.queue(action, vector);
|
||||
}
|
||||
|
||||
final keyTypes = <InputType>[];
|
||||
for (final key in _pressedKeys) {
|
||||
InputAction? keyAction;
|
||||
InputType? keyType = null;
|
||||
Vector3? vector;
|
||||
|
||||
switch (key) {
|
||||
case PhysicalKey.W:
|
||||
keyAction = _actions[InputType.KEYDOWN_W];
|
||||
keyType = InputType.KEYDOWN_W;
|
||||
vector = Vector3(0, 0, -1);
|
||||
break;
|
||||
case PhysicalKey.A:
|
||||
keyAction = _actions[InputType.KEYDOWN_A];
|
||||
keyType = InputType.KEYDOWN_A;
|
||||
vector = Vector3(-1, 0, 0);
|
||||
break;
|
||||
case PhysicalKey.S:
|
||||
keyAction = _actions[InputType.KEYDOWN_S];
|
||||
keyType = InputType.KEYDOWN_S;
|
||||
vector = Vector3(0, 0, 1);
|
||||
break;
|
||||
case PhysicalKey.D:
|
||||
keyAction = _actions[InputType.KEYDOWN_D];
|
||||
keyType = InputType.KEYDOWN_D;
|
||||
vector = Vector3(1, 0, 0);
|
||||
break;
|
||||
}
|
||||
if (keyAction != null) {
|
||||
var transform = _axes[keyAction];
|
||||
if (transform != null) {
|
||||
vector = transform * vector;
|
||||
|
||||
// ignore: unnecessary_null_comparison
|
||||
if (keyType != null) {
|
||||
keyAction = _actions[keyType];
|
||||
|
||||
if (keyAction != null) {
|
||||
var transform = _axes[keyAction];
|
||||
if (transform != null) {
|
||||
vector = transform * vector;
|
||||
}
|
||||
transformDelegate?.queue(keyAction, vector!);
|
||||
keyTypes.add(keyType);
|
||||
}
|
||||
transformDelegate?.queue(keyAction, vector!);
|
||||
}
|
||||
}
|
||||
|
||||
await transformDelegate?.execute();
|
||||
var updates = _inputDeltas.keys.followedBy(keyTypes).toList();
|
||||
if (updates.isNotEmpty) {
|
||||
_gesturesController.add(updates);
|
||||
_cameraUpdatedController.add(true);
|
||||
}
|
||||
|
||||
_inputDeltas.clear();
|
||||
_processing = false;
|
||||
}
|
||||
@@ -160,15 +195,13 @@ class DelegateInputHandler implements InputHandler {
|
||||
}
|
||||
if (isMiddle) {
|
||||
_inputDeltas[InputType.MMB_HOLD_AND_MOVE] =
|
||||
(_inputDeltas[InputType.MMB_HOLD_AND_MOVE] ?? Vector3.zero()) + Vector3(delta.x, delta.y, 0.0);
|
||||
(_inputDeltas[InputType.MMB_HOLD_AND_MOVE] ?? Vector3.zero()) +
|
||||
Vector3(delta.x, delta.y, 0.0);
|
||||
} else {
|
||||
_inputDeltas[InputType.LMB_HOLD_AND_MOVE] =
|
||||
(_inputDeltas[InputType.LMB_HOLD_AND_MOVE] ?? Vector3.zero()) + Vector3(delta.x, delta.y, 0.0);
|
||||
(_inputDeltas[InputType.LMB_HOLD_AND_MOVE] ?? Vector3.zero()) +
|
||||
Vector3(delta.x, delta.y, 0.0);
|
||||
}
|
||||
// else {
|
||||
// _inputDeltas[InputType.POINTER_MOVE] =
|
||||
// (_inputDeltas[InputType.POINTER_MOVE] ?? Vector3.zero()) + delta;
|
||||
// }
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -180,7 +213,8 @@ class DelegateInputHandler implements InputHandler {
|
||||
return;
|
||||
}
|
||||
_inputDeltas[InputType.POINTER_MOVE] =
|
||||
(_inputDeltas[InputType.POINTER_MOVE] ?? Vector3.zero()) + Vector3(delta.x, delta.y, 0.0);
|
||||
(_inputDeltas[InputType.POINTER_MOVE] ?? Vector3.zero()) +
|
||||
Vector3(delta.x, delta.y, 0.0);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -191,8 +225,8 @@ class DelegateInputHandler implements InputHandler {
|
||||
}
|
||||
try {
|
||||
_inputDeltas[InputType.SCROLLWHEEL] =
|
||||
(_inputDeltas[InputType.SCROLLWHEEL] ?? Vector3.zero())
|
||||
+ Vector3(0,0, scrollDelta > 0 ? 1 : -1);
|
||||
(_inputDeltas[InputType.SCROLLWHEEL] ?? Vector3.zero()) +
|
||||
Vector3(0, 0, scrollDelta > 0 ? 1 : -1);
|
||||
} catch (e) {
|
||||
_logger.warning("Error during scroll accumulation: $e");
|
||||
}
|
||||
@@ -206,15 +240,6 @@ class DelegateInputHandler implements InputHandler {
|
||||
@override
|
||||
Future<bool> get initialized => viewer.initialized;
|
||||
|
||||
@override
|
||||
Future<void> onScaleEnd() async {}
|
||||
|
||||
@override
|
||||
Future<void> onScaleStart() async {}
|
||||
|
||||
@override
|
||||
Future<void> onScaleUpdate() async {}
|
||||
|
||||
@override
|
||||
void setActionForType(InputType gestureType, InputAction gestureAction) {
|
||||
_actions[gestureType] = gestureAction;
|
||||
@@ -232,4 +257,26 @@ class DelegateInputHandler implements InputHandler {
|
||||
void keyUp(PhysicalKey key) {
|
||||
_pressedKeys.remove(key);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onScaleEnd(int pointerCount) async {}
|
||||
|
||||
@override
|
||||
Future<void> onScaleStart(Vector2 localPosition, int pointerCount) async {
|
||||
// noop
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta,
|
||||
double horizontalScale, double verticalScale, double scale, int pointerCount) async {
|
||||
if (pointerCount == 1) {
|
||||
_inputDeltas[InputType.SCALE1] =
|
||||
Vector3(focalPointDelta.x, focalPointDelta.y, 0);
|
||||
} else if (pointerCount == 2) {
|
||||
_inputDeltas[InputType.SCALE2] =
|
||||
Vector3(0, 0, max(horizontalScale, verticalScale));
|
||||
} else {
|
||||
throw UnimplementedError("Only pointerCount <= 2 supported");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
class DefaultPickDelegate extends PickDelegate {
|
||||
final ThermionViewer viewer;
|
||||
|
||||
const DefaultPickDelegate(this.viewer);
|
||||
|
||||
@override
|
||||
void pick(Vector2 location) {
|
||||
viewer.pick(location.x.toInt(), location.y.toInt());
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
final ThermionViewer viewer;
|
||||
late Future<Camera> _camera;
|
||||
final double minimumDistance;
|
||||
double? Function(Vector3)? getDistanceToTarget;
|
||||
Future<double?> Function(Vector3)? getDistanceToTarget;
|
||||
|
||||
Vector2 _queuedRotationDelta = Vector2.zero();
|
||||
double _queuedZoomDelta = 0.0;
|
||||
@@ -22,7 +22,14 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
this.getDistanceToTarget,
|
||||
this.minimumDistance = 10.0,
|
||||
}) {
|
||||
_camera = viewer.getMainCamera();
|
||||
_camera = viewer.getMainCamera().then((Camera cam) async {
|
||||
var viewMatrix = makeViewMatrix(Vector3(0.0, 0, -minimumDistance),
|
||||
Vector3.zero(), Vector3(0.0, 1.0, 0.0));
|
||||
viewMatrix.invert();
|
||||
|
||||
await cam.setTransform(viewMatrix);
|
||||
return cam;
|
||||
});
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
@@ -38,24 +45,36 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
_queuedRotationDelta += Vector2(delta.x, delta.y);
|
||||
break;
|
||||
case InputAction.TRANSLATE:
|
||||
_queuedZoomDelta += delta!.z;
|
||||
_queuedZoomDelta += delta.z;
|
||||
break;
|
||||
case InputAction.PICK:
|
||||
// Assuming PICK is used for zoom in this context
|
||||
_queuedZoomDelta += delta.z;
|
||||
break;
|
||||
case InputAction.NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
case InputAction.ZOOM:
|
||||
_queuedZoomDelta += delta.z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool _executing = false;
|
||||
|
||||
@override
|
||||
Future<void> execute() async {
|
||||
if (_queuedRotationDelta.length2 == 0.0 && _queuedZoomDelta == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_executing) {
|
||||
return;
|
||||
}
|
||||
|
||||
_executing = true;
|
||||
|
||||
final view = await viewer.getViewAt(0);
|
||||
final viewport = await view.getViewport();
|
||||
|
||||
var viewMatrix = await viewer.getCameraViewMatrix();
|
||||
var modelMatrix = await viewer.getCameraModelMatrix();
|
||||
var projectionMatrix = await viewer.getCameraProjectionMatrix();
|
||||
@@ -63,15 +82,22 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
Vector3 currentPosition = modelMatrix.getTranslation();
|
||||
|
||||
Vector3 forward = -currentPosition.normalized();
|
||||
|
||||
if (forward.length == 0) {
|
||||
forward = Vector3(0, 0, -1);
|
||||
currentPosition = Vector3(0, 0, minimumDistance);
|
||||
}
|
||||
|
||||
Vector3 right = _up.cross(forward).normalized();
|
||||
Vector3 up = forward.cross(right);
|
||||
|
||||
// Calculate intersection point and depth
|
||||
double radius = getDistanceToTarget?.call(currentPosition) ?? 1.0;
|
||||
if (radius != 1.0) {
|
||||
radius = currentPosition.length - radius;
|
||||
}
|
||||
Vector3 intersection = (-forward).scaled(radius);
|
||||
// Calculate the point where the camera forward ray intersects with the
|
||||
// surface of the target sphere
|
||||
var distanceToTarget =
|
||||
(await getDistanceToTarget?.call(currentPosition)) ?? 0;
|
||||
|
||||
Vector3 intersection =
|
||||
(-forward).scaled(currentPosition.length - distanceToTarget);
|
||||
|
||||
final intersectionInViewSpace = viewMatrix *
|
||||
Vector4(intersection.x, intersection.y, intersection.z, 1.0);
|
||||
@@ -80,12 +106,8 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
intersectionInClipSpace / intersectionInClipSpace.w;
|
||||
|
||||
// Calculate new camera position based on rotation
|
||||
final ndcX = 2 *
|
||||
((-_queuedRotationDelta.x * viewer.pixelRatio) /
|
||||
viewer.viewportDimensions.$1);
|
||||
final ndcY = 2 *
|
||||
((_queuedRotationDelta.y * viewer.pixelRatio) /
|
||||
viewer.viewportDimensions.$2);
|
||||
final ndcX = 2 * ((-_queuedRotationDelta.x) / viewport.width);
|
||||
final ndcY = 2 * ((_queuedRotationDelta.y) / viewport.height);
|
||||
final ndc = Vector4(ndcX, ndcY, intersectionInNdcSpace.z, 1.0);
|
||||
|
||||
var clipSpace = Vector4(
|
||||
@@ -99,17 +121,45 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
var worldSpace3 = worldSpace.xyz.normalized() * currentPosition.length;
|
||||
currentPosition = worldSpace3;
|
||||
|
||||
// Apply zoom
|
||||
// Zoom
|
||||
if (_queuedZoomDelta != 0.0) {
|
||||
Vector3 toSurface = currentPosition - intersection;
|
||||
currentPosition =
|
||||
currentPosition + toSurface.scaled(_queuedZoomDelta * 0.1);
|
||||
}
|
||||
var distToIntersection =
|
||||
(currentPosition - intersection).length - minimumDistance;
|
||||
|
||||
// Ensure minimum distance
|
||||
if (currentPosition.length < radius + minimumDistance) {
|
||||
currentPosition =
|
||||
(currentPosition.normalized() * (radius + minimumDistance));
|
||||
// if we somehow overshot the minimum distance, reset the camera to the minimum distance
|
||||
if (distToIntersection < 0) {
|
||||
currentPosition +=
|
||||
(intersection.normalized().scaled(-distToIntersection * 10));
|
||||
} else {
|
||||
bool zoomingOut = _queuedZoomDelta > 0;
|
||||
late Vector3 offset;
|
||||
|
||||
// when zooming, we don't always use fractions of the distance from
|
||||
// the camera to the target (this is due to float precision issues at
|
||||
// large distances, and also it doesn't work well for UI).
|
||||
|
||||
// if we're zooming out and the distance is less than 10m, we zoom out by 1 unit
|
||||
if (zoomingOut) {
|
||||
if (distToIntersection < 10) {
|
||||
offset = intersection.normalized();
|
||||
} else {
|
||||
offset = intersection.normalized().scaled(distToIntersection / 10);
|
||||
}
|
||||
// if we're zooming in and the distance is less than 5m, zoom in by 1/2 the distance,
|
||||
// otherwise 1/10 of the distance each time
|
||||
} else {
|
||||
if (distToIntersection < 5) {
|
||||
offset = intersection.normalized().scaled(-distToIntersection / 2);
|
||||
} else {
|
||||
offset = intersection.normalized().scaled(-distToIntersection / 10);
|
||||
}
|
||||
|
||||
if (offset.length > distToIntersection) {
|
||||
offset = Vector3.zero();
|
||||
}
|
||||
}
|
||||
currentPosition += offset;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate view matrix
|
||||
@@ -127,5 +177,7 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
|
||||
// Reset queued deltas
|
||||
_queuedRotationDelta = Vector2.zero();
|
||||
_queuedZoomDelta = 0.0;
|
||||
|
||||
_executing = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
||||
static final Vector3 _right = Vector3(1, 0, 0);
|
||||
|
||||
Vector2 _queuedRotationDelta = Vector2.zero();
|
||||
Vector2 _queuedPanDelta = Vector2.zero();
|
||||
Vector3 _queuedTranslateDelta = Vector3.zero();
|
||||
double _queuedZoomDelta = 0.0;
|
||||
Vector3 _queuedMoveDelta = Vector3.zero();
|
||||
|
||||
@@ -49,15 +49,15 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
||||
_queuedRotationDelta += Vector2(delta.x, delta.y);
|
||||
break;
|
||||
case InputAction.TRANSLATE:
|
||||
_queuedPanDelta += Vector2(delta.x, delta.y);
|
||||
_queuedZoomDelta += delta.z;
|
||||
_queuedTranslateDelta += delta;
|
||||
break;
|
||||
case InputAction.PICK:
|
||||
// Assuming PICK is used for zoom in this context
|
||||
_queuedZoomDelta += delta.z;
|
||||
break;
|
||||
case InputAction.NONE:
|
||||
// Do nothing
|
||||
break;
|
||||
case InputAction.ZOOM:
|
||||
_queuedZoomDelta += delta.z;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -73,7 +73,7 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
||||
_executing = true;
|
||||
|
||||
if (_queuedRotationDelta.length2 == 0.0 &&
|
||||
_queuedPanDelta.length2 == 0.0 &&
|
||||
_queuedTranslateDelta.length2 == 0.0 &&
|
||||
_queuedZoomDelta == 0.0 &&
|
||||
_queuedMoveDelta.length2 == 0.0) {
|
||||
_executing = false;
|
||||
@@ -81,48 +81,43 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
||||
}
|
||||
|
||||
final activeCamera = await viewer.getActiveCamera();
|
||||
Matrix4 currentViewMatrix = activeCamera.getViewMatrix();
|
||||
|
||||
|
||||
Matrix4 currentTransform = await viewer.getLocalTransform(await entity);
|
||||
Vector3 currentPosition = currentTransform.getTranslation();
|
||||
|
||||
Quaternion currentRotation =
|
||||
Quaternion.fromRotation(currentTransform.getRotation());
|
||||
|
||||
// Calculate relative transform
|
||||
Matrix4 relativeTransform = Matrix4.identity();
|
||||
Vector3 relativeTranslation = Vector3.zero();
|
||||
Quaternion relativeRotation = Quaternion.identity();
|
||||
|
||||
// Apply rotation
|
||||
if (_queuedRotationDelta.length2 > 0.0) {
|
||||
double deltaX =
|
||||
_queuedRotationDelta.x * rotationSensitivity * viewer.pixelRatio;
|
||||
double deltaY =
|
||||
_queuedRotationDelta.y * rotationSensitivity * viewer.pixelRatio;
|
||||
double deltaX = _queuedRotationDelta.x * rotationSensitivity;
|
||||
double deltaY = _queuedRotationDelta.y * rotationSensitivity;
|
||||
|
||||
Quaternion yawRotation = Quaternion.axisAngle(_up, -deltaX);
|
||||
Quaternion pitchRotation = Quaternion.axisAngle(_right, -deltaY);
|
||||
|
||||
currentRotation = currentRotation * pitchRotation * yawRotation;
|
||||
currentRotation.normalize();
|
||||
|
||||
relativeRotation = pitchRotation * yawRotation;
|
||||
_queuedRotationDelta = Vector2.zero();
|
||||
}
|
||||
|
||||
// Apply pan
|
||||
if (_queuedPanDelta.length2 > 0.0) {
|
||||
Vector3 right = _right.clone()..applyQuaternion(currentRotation);
|
||||
Vector3 up = _up.clone()..applyQuaternion(currentRotation);
|
||||
if (_queuedTranslateDelta.length2 > 0.0) {
|
||||
double deltaX = _queuedTranslateDelta.x * panSensitivity;
|
||||
double deltaY = _queuedTranslateDelta.y * panSensitivity;
|
||||
double deltaZ = -_queuedTranslateDelta.z * panSensitivity;
|
||||
|
||||
double deltaX = _queuedPanDelta.x * panSensitivity * viewer.pixelRatio;
|
||||
double deltaY = _queuedPanDelta.y * panSensitivity * viewer.pixelRatio;
|
||||
|
||||
Vector3 panOffset = right * deltaX + up * deltaY;
|
||||
currentPosition += panOffset;
|
||||
|
||||
_queuedPanDelta = Vector2.zero();
|
||||
relativeTranslation += _right * deltaX + _up * deltaY + _forward * deltaZ;
|
||||
_queuedTranslateDelta = Vector3.zero();
|
||||
}
|
||||
|
||||
// Apply zoom
|
||||
if (_queuedZoomDelta != 0.0) {
|
||||
Vector3 forward = _forward.clone()..applyQuaternion(currentRotation);
|
||||
currentPosition += forward * -_queuedZoomDelta * zoomSensitivity;
|
||||
relativeTranslation += forward * -_queuedZoomDelta * zoomSensitivity;
|
||||
_queuedZoomDelta = 0.0;
|
||||
}
|
||||
|
||||
@@ -132,21 +127,38 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
||||
Vector3 right = _right.clone()..applyQuaternion(currentRotation);
|
||||
Vector3 up = _up.clone()..applyQuaternion(currentRotation);
|
||||
|
||||
Vector3 moveOffset = right * _queuedMoveDelta.x +
|
||||
up * _queuedMoveDelta.y +
|
||||
forward * _queuedMoveDelta.z;
|
||||
currentPosition += moveOffset;
|
||||
relativeTranslation += (right * _queuedMoveDelta.x +
|
||||
up * _queuedMoveDelta.y +
|
||||
forward * _queuedMoveDelta.z) *
|
||||
movementSensitivity;
|
||||
|
||||
_queuedMoveDelta = Vector3.zero();
|
||||
}
|
||||
|
||||
// Constrain position
|
||||
currentPosition = _constrainPosition(currentPosition);
|
||||
// If the managed entity is not the active camera, we need to apply the rotation from the current camera model matrix
|
||||
// to the entity's translation
|
||||
if (await entity != activeCamera.getEntity()) {
|
||||
Matrix4 modelMatrix = await activeCamera.getModelMatrix();
|
||||
relativeTranslation = modelMatrix.getRotation() * relativeTranslation;
|
||||
}
|
||||
|
||||
// Compose relative transform
|
||||
relativeTransform = Matrix4.compose(
|
||||
relativeTranslation, relativeRotation, Vector3(1, 1, 1));
|
||||
|
||||
// Apply relative transform to current transform
|
||||
Matrix4 newTransform = currentTransform * relativeTransform;
|
||||
|
||||
// Extract new position and constrain it
|
||||
Vector3 newPosition = newTransform.getTranslation();
|
||||
newPosition = _constrainPosition(newPosition);
|
||||
|
||||
// Recompose final transform with constrained position
|
||||
Matrix4 finalTransform = Matrix4.compose(newPosition,
|
||||
Quaternion.fromRotation(newTransform.getRotation()), Vector3(1, 1, 1));
|
||||
|
||||
// Update camera
|
||||
Matrix4 newModelMatrix =
|
||||
Matrix4.compose(currentPosition, currentRotation, Vector3(1, 1, 1));
|
||||
await viewer.setTransform(await entity, newModelMatrix);
|
||||
await viewer.setTransform(await entity, finalTransform);
|
||||
|
||||
_executing = false;
|
||||
}
|
||||
|
||||
@@ -29,13 +29,16 @@ class OverTheShoulderCameraDelegate implements InputHandlerDelegate {
|
||||
final cameraUp = Vector3(0, 1, 0);
|
||||
var cameraLookAt = Vector3(0, 0.5, 3);
|
||||
|
||||
final void Function(Matrix4 transform)? onUpdate;
|
||||
|
||||
OverTheShoulderCameraDelegate(this.viewer, this.player, this.camera,
|
||||
{this.rotationSensitivity = 0.001,
|
||||
this.movementSensitivity = 0.1,
|
||||
this.zoomSensitivity = 0.1,
|
||||
this.panSensitivity = 0.1,
|
||||
this.clampY,
|
||||
ThermionEntity? entity}) {}
|
||||
ThermionEntity? entity,
|
||||
this.onUpdate}) {}
|
||||
|
||||
@override
|
||||
Future<void> queue(InputAction action, Vector3? delta) async {
|
||||
@@ -53,6 +56,8 @@ class OverTheShoulderCameraDelegate implements InputHandlerDelegate {
|
||||
break;
|
||||
case InputAction.NONE:
|
||||
break;
|
||||
case InputAction.ZOOM:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +96,15 @@ class OverTheShoulderCameraDelegate implements InputHandlerDelegate {
|
||||
var inverted = newPlayerTransform.clone()..invert();
|
||||
|
||||
// camera is always looking at -Z, whereas models generally face towards +Z
|
||||
// therefore
|
||||
if (_queuedRotationDelta.length2 > 0.0) {
|
||||
double deltaX =
|
||||
_queuedRotationDelta.x * rotationSensitivity * viewer.pixelRatio;
|
||||
_queuedRotationDelta.x * rotationSensitivity;
|
||||
double deltaY =
|
||||
_queuedRotationDelta.y * rotationSensitivity * viewer.pixelRatio;
|
||||
_queuedRotationDelta.y * rotationSensitivity;
|
||||
|
||||
cameraLookAt = Matrix4.rotationY(-deltaX) * Matrix4.rotationX(-deltaY) * cameraLookAt;
|
||||
cameraLookAt = Matrix4.rotationY(-deltaX) *
|
||||
Matrix4.rotationX(-deltaY) *
|
||||
cameraLookAt;
|
||||
_queuedRotationDelta = Vector2.zero();
|
||||
}
|
||||
|
||||
@@ -110,85 +116,7 @@ class OverTheShoulderCameraDelegate implements InputHandlerDelegate {
|
||||
|
||||
await viewer.queueTransformUpdates(
|
||||
[camera.getEntity(), player], [newCameraTransform, newPlayerTransform]);
|
||||
|
||||
onUpdate?.call(newPlayerTransform);
|
||||
_executing = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Quaternion relativeCameraRotation = Quaternion.identity();
|
||||
|
||||
// // Apply rotation
|
||||
|
||||
|
||||
// // transform the translation from player space to world space
|
||||
// var rotation = (await camera.getModelMatrix()).getRotation();
|
||||
// // Extract yaw angle from the original matrix
|
||||
// double yaw = atan2(rotation.entry(2, 0), rotation.entry(0, 0));
|
||||
|
||||
// // Create a new matrix with only the yaw rotation
|
||||
// double cosYaw = cos(yaw);
|
||||
// double sinYaw = sin(yaw);
|
||||
|
||||
// rotation = Matrix3(cosYaw, 0, sinYaw, 0, 1, 0, -sinYaw, 0, cosYaw);
|
||||
|
||||
// relativeTranslation = rotation * relativeTranslation;
|
||||
|
||||
// // Compose relative transform
|
||||
// relativeTransform =
|
||||
// Matrix4.compose(relativeTranslation, currentRotation, Vector3(1, 1, 1));
|
||||
|
||||
// // Apply relative transform to current transform
|
||||
// Matrix4 newTransform = currentTransform * relativeTransform;
|
||||
|
||||
// // Extract new position and constrain it
|
||||
// Vector3 newPosition = newTransform.getTranslation();
|
||||
|
||||
// // Recompose final transform with constrained position
|
||||
// Matrix4 finalTransform = Matrix4.compose(newPosition,
|
||||
// Quaternion.fromRotation(newTransform.getRotation()), Vector3(1, 1, 1));
|
||||
|
||||
// Quaternion relativeCameraRotation = Quaternion.identity();
|
||||
|
||||
// // Apply rotation
|
||||
// if (_queuedRotationDelta.length2 > 0.0) {
|
||||
// double deltaX =
|
||||
// _queuedRotationDelta.x * rotationSensitivity * viewer.pixelRatio;
|
||||
// double deltaY =
|
||||
// _queuedRotationDelta.y * rotationSensitivity * viewer.pixelRatio;
|
||||
|
||||
// Quaternion yawRotation = Quaternion.axisAngle(_up, -deltaX);
|
||||
// Quaternion pitchRotation = Quaternion.axisAngle(_right, -deltaY);
|
||||
|
||||
// relativeCameraRotation = pitchRotation * yawRotation;
|
||||
// _queuedRotationDelta = Vector2.zero();
|
||||
// }
|
||||
|
||||
// // transform the translation from player space to world space
|
||||
// var rotation = (await camera.getModelMatrix()).getRotation();
|
||||
// // Extract yaw angle from the original matrix
|
||||
// double yaw = atan2(rotation.entry(2, 0), rotation.entry(0, 0));
|
||||
|
||||
// // Create a new matrix with only the yaw rotation
|
||||
// double cosYaw = cos(yaw);
|
||||
// double sinYaw = sin(yaw);
|
||||
|
||||
// rotation = Matrix3(cosYaw, 0, sinYaw, 0, 1, 0, -sinYaw, 0, cosYaw);
|
||||
|
||||
// relativeTranslation = rotation * relativeTranslation;
|
||||
|
||||
// // Compose relative transform
|
||||
// relativeTransform =
|
||||
// Matrix4.compose(relativeTranslation, currentRotation, Vector3(1, 1, 1));
|
||||
|
||||
// // Apply relative transform to current transform
|
||||
// Matrix4 newTransform = currentTransform * relativeTransform;
|
||||
|
||||
// // Extract new position and constrain it
|
||||
// Vector3 newPosition = newTransform.getTranslation();
|
||||
|
||||
// // Recompose final transform with constrained position
|
||||
// Matrix4 finalTransform = Matrix4.compose(newPosition,
|
||||
// Quaternion.fromRotation(newTransform.getRotation()), Vector3(1, 1, 1));
|
||||
|
||||
// // Update camera
|
||||
@@ -24,18 +24,20 @@ enum InputType {
|
||||
|
||||
enum PhysicalKey { W, A, S, D }
|
||||
|
||||
enum InputAction { TRANSLATE, ROTATE, PICK, NONE }
|
||||
enum InputAction { TRANSLATE, ROTATE, PICK, ZOOM, NONE }
|
||||
|
||||
abstract class InputHandler {
|
||||
|
||||
Stream get cameraUpdated;
|
||||
|
||||
Future<void> onPointerHover(Vector2 localPosition, Vector2 delta);
|
||||
Future<void> onPointerScroll(Vector2 localPosition, double scrollDelta);
|
||||
Future<void> onPointerDown(Vector2 localPosition, bool isMiddle);
|
||||
Future<void> onPointerMove(Vector2 localPosition, Vector2 delta, bool isMiddle);
|
||||
Future<void> onPointerMove(
|
||||
Vector2 localPosition, Vector2 delta, bool isMiddle);
|
||||
Future<void> onPointerUp(bool isMiddle);
|
||||
Future<void> onScaleStart();
|
||||
Future<void> onScaleUpdate();
|
||||
Future<void> onScaleEnd();
|
||||
Future<void> onScaleStart(Vector2 focalPoint, int pointerCount);
|
||||
Future<void> onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, double horizontalScale, double verticalScale, double scale, int pointerCount);
|
||||
Future<void> onScaleEnd(int pointerCount);
|
||||
Future<bool> get initialized;
|
||||
Future dispose();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
44
thermion_dart/lib/src/utils/src/axis.dart
Normal file
44
thermion_dart/lib/src/utils/src/axis.dart
Normal file
@@ -0,0 +1,44 @@
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../../viewer/viewer.dart';
|
||||
|
||||
class Axis {
|
||||
final ThermionViewer _viewer;
|
||||
final ThermionEntity xAxis;
|
||||
final ThermionEntity yAxis;
|
||||
final ThermionEntity zAxis;
|
||||
|
||||
Axis._(this.xAxis, this.yAxis, this.zAxis, this._viewer);
|
||||
|
||||
static Future<Axis> create(ThermionViewer viewer) async {
|
||||
final xAxis = await viewer!.createGeometry(
|
||||
Geometry(Float32List.fromList([0, 0, 0, 10, 0, 0]), [0, 1],
|
||||
primitiveType: PrimitiveType.LINES),
|
||||
materialInstance: await viewer!.createUnlitMaterialInstance());
|
||||
final yAxis = await viewer!.createGeometry(
|
||||
Geometry(Float32List.fromList([0, 0, 0, 0, 10, 0]), [0, 1],
|
||||
primitiveType: PrimitiveType.LINES),
|
||||
materialInstance: await viewer!.createUnlitMaterialInstance());
|
||||
final zAxis = await viewer!.createGeometry(
|
||||
Geometry(Float32List.fromList([0, 0, 0, 0, 0, 10]), [0, 1],
|
||||
primitiveType: PrimitiveType.LINES),
|
||||
materialInstance: await viewer!.createUnlitMaterialInstance());
|
||||
|
||||
await viewer!.setMaterialPropertyFloat4(
|
||||
xAxis, "baseColorFactor", 0, 1.0, 0.0, 0.0, 1.0);
|
||||
await viewer!.setMaterialPropertyFloat4(
|
||||
yAxis, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
|
||||
await viewer!.setMaterialPropertyFloat4(
|
||||
zAxis, "baseColorFactor", 0, 0.0, 0.0, 1.0, 1.0);
|
||||
return Axis._(xAxis, yAxis, zAxis, viewer);
|
||||
}
|
||||
|
||||
Future setTransform(Matrix4 transform) async {
|
||||
await _viewer.setTransform(xAxis, transform);
|
||||
await _viewer.setTransform(yAxis, transform);
|
||||
await _viewer.setTransform(zAxis, transform);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import 'dart:io';
|
||||
|
||||
import 'package:ffi/ffi.dart';
|
||||
|
||||
import '../viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import '../../viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
|
||||
class DartResourceLoader {
|
||||
static final _assets = <int, Pointer>{};
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import '../../thermion_dart.dart';
|
||||
import '../../../thermion_dart.dart';
|
||||
|
||||
class GeometryHelper {
|
||||
static Geometry sphere({bool normals = true, bool uvs = true}) {
|
||||
@@ -1,19 +1,31 @@
|
||||
import 'dart:async';
|
||||
import 'package:thermion_dart/src/entities/abstract_gizmo.dart';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/viewer.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import '../viewer/viewer.dart';
|
||||
|
||||
class Gizmo extends AbstractGizmo {
|
||||
abstract class Gizmo {
|
||||
bool get isVisible;
|
||||
bool get isHovered;
|
||||
|
||||
void reset();
|
||||
|
||||
Future attach(ThermionEntity entity);
|
||||
Future detach();
|
||||
|
||||
Stream<Aabb2> get boundingBox;
|
||||
|
||||
void checkHover(int x, int y);
|
||||
}
|
||||
|
||||
abstract class BaseGizmo extends Gizmo {
|
||||
final ThermionEntity x;
|
||||
final ThermionEntity y;
|
||||
final ThermionEntity z;
|
||||
final ThermionEntity center;
|
||||
|
||||
final ThermionViewer _viewer;
|
||||
|
||||
ThermionEntity? _activeAxis;
|
||||
ThermionEntity? _activeEntity;
|
||||
ThermionViewer viewer;
|
||||
|
||||
bool _visible = false;
|
||||
bool get isVisible => _visible;
|
||||
@@ -26,10 +38,9 @@ class Gizmo extends AbstractGizmo {
|
||||
Stream<Aabb2> get boundingBox => _boundingBoxController.stream;
|
||||
final _boundingBoxController = StreamController<Aabb2>.broadcast();
|
||||
|
||||
Gizmo(this.x, this.y, this.z, this.center, this._viewer,
|
||||
{this.ignore = const <ThermionEntity>{}}) {
|
||||
_viewer.gizmoPickResult.listen(_onGizmoPickResult);
|
||||
_viewer.pickResult.listen(_onPickResult);
|
||||
BaseGizmo({required this.x, required this.y, required this.z, required this.center, required this.viewer,
|
||||
this.ignore = const <ThermionEntity>{}}) {
|
||||
onPick(_onGizmoPickResult);
|
||||
}
|
||||
|
||||
final _stopwatch = Stopwatch();
|
||||
@@ -52,12 +63,10 @@ class Gizmo extends AbstractGizmo {
|
||||
final axis = Vector3(_activeAxis == x ? 1.0 : 0.0,
|
||||
_activeAxis == y ? 1.0 : 0.0, _activeAxis == z ? 1.0 : 0.0);
|
||||
|
||||
await _viewer.queueRelativePositionUpdateWorldAxis(
|
||||
await viewer.queueRelativePositionUpdateWorldAxis(
|
||||
_activeEntity!,
|
||||
_transX * _viewer.pixelRatio,
|
||||
-_transY *
|
||||
_viewer
|
||||
.pixelRatio, // flip the sign because "up" in NDC Y axis is positive, but negative in Flutter
|
||||
_transX,
|
||||
-_transY, // flip the sign because "up" in NDC Y axis is positive, but negative in Flutter
|
||||
axis.x,
|
||||
axis.y,
|
||||
axis.z);
|
||||
@@ -70,10 +79,6 @@ class Gizmo extends AbstractGizmo {
|
||||
_activeAxis = null;
|
||||
}
|
||||
|
||||
void _onPickResult(FilamentPickResult result) async {
|
||||
await attach(result.entity);
|
||||
}
|
||||
|
||||
void _onGizmoPickResult(FilamentPickResult result) async {
|
||||
if (result.entity == x || result.entity == y || result.entity == z) {
|
||||
_activeAxis = result.entity;
|
||||
@@ -98,21 +103,25 @@ class Gizmo extends AbstractGizmo {
|
||||
_visible = true;
|
||||
|
||||
if (_activeEntity != null) {
|
||||
await _viewer.removeStencilHighlight(_activeEntity!);
|
||||
await viewer.removeStencilHighlight(_activeEntity!);
|
||||
}
|
||||
_activeEntity = entity;
|
||||
await _viewer.setGizmoVisibility(true);
|
||||
await _viewer.setParent(center, entity, preserveScaling: false);
|
||||
_boundingBoxController.sink.add(await _viewer.getViewportBoundingBox(x));
|
||||
|
||||
await viewer.setParent(center, entity, preserveScaling: false);
|
||||
_boundingBoxController.sink.add(await viewer.getViewportBoundingBox(x));
|
||||
}
|
||||
|
||||
Future detach() async {
|
||||
await _viewer.setGizmoVisibility(false);
|
||||
await setVisibility(false);
|
||||
}
|
||||
|
||||
@override
|
||||
void checkHover(double x, double y) {
|
||||
_viewer.pickGizmo(x.toInt(), y.toInt());
|
||||
void checkHover(int x, int y) {
|
||||
pick(x, y);
|
||||
}
|
||||
|
||||
Future pick(int x, int y);
|
||||
|
||||
Future setVisibility(bool visible);
|
||||
void onPick(void Function(PickResult result) callback);
|
||||
}
|
||||
4
thermion_dart/lib/src/utils/utils.dart
Normal file
4
thermion_dart/lib/src/utils/utils.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
library;
|
||||
|
||||
export 'src/geometry.dart';
|
||||
export 'src/axis.dart';
|
||||
@@ -26,7 +26,7 @@ Future<void> withVoidCallback(
|
||||
nativeCallable.close();
|
||||
}
|
||||
|
||||
Future<int> withPointerCallback<T extends NativeType>(
|
||||
Future<Pointer<T>> withPointerCallback<T extends NativeType>(
|
||||
Function(Pointer<NativeFunction<Void Function(Pointer<T>)>>)
|
||||
func) async {
|
||||
final completer = Completer<Pointer<T>>();
|
||||
@@ -39,7 +39,7 @@ Future<int> withPointerCallback<T extends NativeType>(
|
||||
func.call(nativeCallable.nativeFunction);
|
||||
var ptr = await completer.future;
|
||||
nativeCallable.close();
|
||||
return ptr.address;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
Future<bool> withBoolCallback(
|
||||
|
||||
@@ -2,34 +2,34 @@ import 'dart:ffi';
|
||||
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../../../../utils/matrix.dart';
|
||||
import '../../../../utils/src/matrix.dart';
|
||||
import '../../thermion_viewer_base.dart';
|
||||
import 'thermion_dart.g.dart';
|
||||
import 'thermion_dart.g.dart' as g;
|
||||
|
||||
class ThermionFFICamera extends Camera {
|
||||
final Pointer<TCamera> camera;
|
||||
final Pointer<TEngine> engine;
|
||||
class FFICamera extends Camera {
|
||||
final Pointer<g.TCamera> camera;
|
||||
final Pointer<g.TEngine> engine;
|
||||
late ThermionEntity _entity;
|
||||
|
||||
ThermionFFICamera(this.camera, this.engine) {
|
||||
_entity = Camera_getEntity(camera);
|
||||
FFICamera(this.camera, this.engine) {
|
||||
_entity = g.Camera_getEntity(camera);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setProjectionMatrixWithCulling(
|
||||
Matrix4 projectionMatrix, double near, double far) async {
|
||||
Camera_setCustomProjectionWithCulling(
|
||||
g.Camera_setCustomProjectionWithCulling(
|
||||
camera, matrix4ToDouble4x4(projectionMatrix), near, far);
|
||||
}
|
||||
|
||||
Future<Matrix4> getModelMatrix() async {
|
||||
return double4x4ToMatrix4(Camera_getModelMatrix(camera));
|
||||
return double4x4ToMatrix4(g.Camera_getModelMatrix(camera));
|
||||
}
|
||||
|
||||
@override
|
||||
Future setTransform(Matrix4 transform) async {
|
||||
var entity = Camera_getEntity(camera);
|
||||
Engine_setTransform(engine, entity, matrix4ToDouble4x4(transform));
|
||||
var entity = g.Camera_getEntity(camera);
|
||||
g.Engine_setTransform(engine, entity, matrix4ToDouble4x4(transform));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -38,7 +38,7 @@ class ThermionFFICamera extends Camera {
|
||||
double far = kFar,
|
||||
double aspect = 1.0,
|
||||
double focalLength = kFocalLength}) async {
|
||||
Camera_setLensProjection(camera, near, far, aspect, focalLength);
|
||||
g.Camera_setLensProjection(camera, near, far, aspect, focalLength);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -48,13 +48,13 @@ class ThermionFFICamera extends Camera {
|
||||
|
||||
@override
|
||||
Future setModelMatrix(Matrix4 matrix) async {
|
||||
Camera_setModelMatrix(camera, matrix4ToDouble4x4(matrix));
|
||||
g.Camera_setModelMatrix(camera, matrix4ToDouble4x4(matrix));
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is ThermionFFICamera &&
|
||||
other is FFICamera &&
|
||||
runtimeType == other.runtimeType &&
|
||||
camera == other.camera;
|
||||
|
||||
@@ -63,21 +63,29 @@ class ThermionFFICamera extends Camera {
|
||||
|
||||
@override
|
||||
Future<double> getCullingFar() async {
|
||||
return Camera_getCullingFar(camera);
|
||||
return g.Camera_getCullingFar(camera);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getNear() async {
|
||||
return Camera_getNear(camera);
|
||||
return g.Camera_getNear(camera);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getFocalLength() async {
|
||||
return Camera_getFocalLength(camera);
|
||||
return g.Camera_getFocalLength(camera);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Matrix4> getViewMatrix() async {
|
||||
return double4x4ToMatrix4(Camera_getViewMatrix(camera));
|
||||
return double4x4ToMatrix4(g.Camera_getViewMatrix(camera));
|
||||
}
|
||||
|
||||
@override
|
||||
Future setProjection(Projection projection, double left, double right,
|
||||
double bottom, double top, double near, double far) async {
|
||||
var pType = g.Projection.values[projection.index];
|
||||
g.Camera_setProjection(camera, pType, left,
|
||||
right, bottom, top, near, far);
|
||||
}
|
||||
}
|
||||
50
thermion_dart/lib/src/viewer/src/ffi/src/ffi_gizmo.dart
Normal file
50
thermion_dart/lib/src/viewer/src/ffi/src/ffi_gizmo.dart
Normal file
@@ -0,0 +1,50 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
|
||||
import '../../../../utils/src/gizmo.dart';
|
||||
import '../../../viewer.dart';
|
||||
|
||||
class FFIGizmo extends BaseGizmo {
|
||||
Pointer<TGizmo> pointer;
|
||||
|
||||
late NativeCallable<GizmoPickCallbackFunction> _nativeCallback;
|
||||
FFIGizmo(
|
||||
this.pointer, ThermionViewer viewer) : super(x: 0, y: 0, z: 0, center: 0, viewer: viewer) {
|
||||
_nativeCallback =
|
||||
NativeCallable<GizmoPickCallbackFunction>.listener(_onPickResult);
|
||||
}
|
||||
|
||||
///
|
||||
/// The result(s) of calling [pickGizmo] (see below).
|
||||
///
|
||||
// Stream<PickResult> get onPick => _pickResultController.stream;
|
||||
// final _pickResultController = StreamController<PickResult>.broadcast();
|
||||
|
||||
void Function(PickResult)? _callback;
|
||||
|
||||
void onPick(void Function(PickResult) callback) {
|
||||
_callback = callback;
|
||||
}
|
||||
|
||||
void _onPickResult(DartEntityId entityId, int x, int y, Pointer<TView> view) {
|
||||
_callback?.call((entity: entityId, x: x, y: y));
|
||||
}
|
||||
|
||||
///
|
||||
/// Used to test whether a Gizmo is at the given viewport coordinates.
|
||||
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method.
|
||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||
///
|
||||
@override
|
||||
Future pick(int x, int y) async {
|
||||
Gizmo_pick(pointer, x.toInt(), y, _nativeCallback.nativeFunction);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setVisibility(bool visible) async {
|
||||
Gizmo_setVisibility(pointer, visible);
|
||||
}
|
||||
}
|
||||
69
thermion_dart/lib/src/viewer/src/ffi/src/ffi_view.dart
Normal file
69
thermion_dart/lib/src/viewer/src/ffi/src/ffi_view.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'dart:ffi';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart';
|
||||
import 'ffi_camera.dart';
|
||||
import 'thermion_viewer_ffi.dart';
|
||||
|
||||
class FFIView extends View {
|
||||
final Pointer<TView> view;
|
||||
final Pointer<TViewer> viewer;
|
||||
|
||||
FFIView(this.view, this.viewer);
|
||||
|
||||
@override
|
||||
Future updateViewport(int width, int height) async {
|
||||
View_updateViewport(view, width, height);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setRenderTarget(covariant FFIRenderTarget renderTarget) async {
|
||||
View_setRenderTarget(view, renderTarget.renderTarget);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setCamera(FFICamera camera) async {
|
||||
View_setCamera(view, camera.camera);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Viewport> getViewport() async {
|
||||
TViewport vp = View_getViewport(view);
|
||||
return Viewport(vp.left, vp.bottom, vp.width, vp.height);
|
||||
}
|
||||
|
||||
@override
|
||||
Camera getCamera() {
|
||||
final engine = Viewer_getEngine(viewer);
|
||||
return FFICamera(View_getCamera(view), engine);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async {
|
||||
View_setAntiAliasing(view, msaa, fxaa, taa);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setPostProcessing(bool enabled) async {
|
||||
View_setPostProcessing(view, enabled);
|
||||
}
|
||||
|
||||
Future setRenderable(bool renderable, FFISwapChain swapChain) async {
|
||||
Viewer_setViewRenderable(viewer, swapChain.swapChain, view, renderable);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setFrustumCullingEnabled(bool enabled) async {
|
||||
View_setFrustumCullingEnabled(view, enabled);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setBloom(double strength) async {
|
||||
View_setBloom(view, strength);
|
||||
}
|
||||
|
||||
@override
|
||||
Future setToneMapper(ToneMapper mapper) async {
|
||||
final engine = await Viewer_getEngine(viewer);
|
||||
View_setToneMappingRenderThread(view, engine, mapper.index);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +1,20 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_gizmo.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'package:vector_math/vector_math_64.dart' as v64;
|
||||
import '../../../../entities/gizmo.dart';
|
||||
import '../../../../utils/matrix.dart';
|
||||
import '../../../../utils/src/gizmo.dart';
|
||||
import '../../../../utils/src/matrix.dart';
|
||||
import '../../events.dart';
|
||||
import '../../shared_types/camera.dart';
|
||||
import '../../shared_types/view.dart';
|
||||
import '../../thermion_viewer_base.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'callbacks.dart';
|
||||
import 'camera_ffi.dart';
|
||||
import 'thermion_dart.g.dart';
|
||||
import 'ffi_camera.dart';
|
||||
import 'ffi_view.dart';
|
||||
|
||||
// ignore: constant_identifier_names
|
||||
const ThermionEntity _FILAMENT_ASSET_ERROR = 0;
|
||||
@@ -24,8 +24,6 @@ typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
|
||||
class ThermionViewerFFI extends ThermionViewer {
|
||||
final _logger = Logger("ThermionViewerFFI");
|
||||
|
||||
double pixelRatio = 1.0;
|
||||
|
||||
Pointer<TSceneManager>? _sceneManager;
|
||||
|
||||
Pointer<TViewer>? _viewer;
|
||||
@@ -86,25 +84,47 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
this._sharedContext = sharedContext ?? nullptr;
|
||||
|
||||
_onPickResultCallable =
|
||||
NativeCallable<Void Function(EntityId entityId, Int x, Int y)>.listener(
|
||||
NativeCallable<Void Function(EntityId entityId, Int x, Int y, Pointer<TView> view)>.listener(
|
||||
_onPickResult);
|
||||
|
||||
_onGizmoPickResultCallable =
|
||||
NativeCallable<Void Function(EntityId entityId, Int x, Int y)>.listener(
|
||||
_onGizmoPickResult);
|
||||
|
||||
_initialize();
|
||||
}
|
||||
|
||||
Future createRenderTarget(
|
||||
double width, double height, int textureHandle) async {
|
||||
await withVoidCallback((callback) => create_render_target_render_thread(
|
||||
_viewer!, textureHandle, width.toInt(), height.toInt(), callback));
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(
|
||||
int width, int height, int textureHandle) async {
|
||||
final renderTarget =
|
||||
Viewer_createRenderTarget(_viewer!, textureHandle, width, height);
|
||||
return FFIRenderTarget(renderTarget, _viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderTarget(FFIRenderTarget renderTarget) async {
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
View_setRenderTarget(view.view, renderTarget.renderTarget);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> createView() async {
|
||||
var view = Viewer_createView(_viewer!);
|
||||
if (view == nullptr) {
|
||||
throw Exception("Failed to create view");
|
||||
}
|
||||
return FFIView(view, _viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future updateViewportAndCameraProjection(double width, double height) async {
|
||||
viewportDimensions = (width * pixelRatio, height * pixelRatio);
|
||||
update_viewport(_viewer!, width.toInt(), height.toInt());
|
||||
var mainView = FFIView(Viewer_getViewAt(_viewer!, 0), _viewer!);
|
||||
mainView.updateViewport(width.toInt(), height.toInt());
|
||||
|
||||
final cameraCount = await getCameraCount();
|
||||
|
||||
@@ -119,7 +139,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
far = kFar;
|
||||
}
|
||||
|
||||
var aspect = viewportDimensions.$1 / viewportDimensions.$2;
|
||||
var aspect = width / height;
|
||||
var focalLength = await camera.getFocalLength();
|
||||
if (focalLength.abs() < 0.1) {
|
||||
focalLength = kFocalLength;
|
||||
@@ -129,18 +149,26 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
}
|
||||
|
||||
Future createSwapChain(double width, double height,
|
||||
{Pointer<Void>? surface}) async {
|
||||
await withVoidCallback((callback) {
|
||||
create_swap_chain_render_thread(_viewer!, surface ?? nullptr,
|
||||
width.toInt(), height.toInt(), callback);
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height) async {
|
||||
var swapChain = await withPointerCallback<TSwapChain>((callback) {
|
||||
return Viewer_createHeadlessSwapChainRenderThread(
|
||||
_viewer!, width, height, callback);
|
||||
});
|
||||
return FFISwapChain(swapChain, _viewer!);
|
||||
}
|
||||
|
||||
Future destroySwapChain() async {
|
||||
await withVoidCallback((callback) {
|
||||
destroy_swap_chain_render_thread(_viewer!, callback);
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createSwapChain(int surface) async {
|
||||
var swapChain = await withPointerCallback<TSwapChain>((callback) {
|
||||
return Viewer_createSwapChainRenderThread(
|
||||
_viewer!, Pointer<Void>.fromAddress(surface), callback);
|
||||
});
|
||||
return FFISwapChain(swapChain, _viewer!);
|
||||
}
|
||||
|
||||
Gizmo? _gizmo;
|
||||
@@ -150,18 +178,12 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
final uberarchivePtr =
|
||||
uberArchivePath?.toNativeUtf8(allocator: allocator).cast<Char>() ??
|
||||
nullptr;
|
||||
var viewer = await withPointerCallback(
|
||||
_viewer = await withPointerCallback(
|
||||
(Pointer<NativeFunction<Void Function(Pointer<TViewer>)>> callback) {
|
||||
create_filament_viewer_render_thread(
|
||||
_sharedContext,
|
||||
_driver,
|
||||
uberarchivePtr,
|
||||
resourceLoader,
|
||||
_renderCallback,
|
||||
_renderCallbackOwner,
|
||||
callback);
|
||||
Viewer_createOnRenderThread(_sharedContext, _driver, uberarchivePtr,
|
||||
resourceLoader, _renderCallback, _renderCallbackOwner, callback);
|
||||
});
|
||||
_viewer = Pointer.fromAddress(viewer);
|
||||
|
||||
allocator.free(uberarchivePtr);
|
||||
if (_viewer!.address == 0) {
|
||||
throw Exception("Failed to create viewer. Check logs for details");
|
||||
@@ -169,13 +191,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
|
||||
_sceneManager = Viewer_getSceneManager(_viewer!);
|
||||
|
||||
await setCameraManipulatorOptions(zoomSpeed: 1.0);
|
||||
|
||||
final gizmoEntities = allocator<Int32>(4);
|
||||
get_gizmo(_sceneManager!, gizmoEntities);
|
||||
_gizmo = Gizmo(gizmoEntities[0], gizmoEntities[1], gizmoEntities[2],
|
||||
gizmoEntities[3], this);
|
||||
allocator.free(gizmoEntities);
|
||||
this._initialized.complete(true);
|
||||
}
|
||||
|
||||
@@ -202,25 +217,37 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future render() async {
|
||||
render_render_thread(_viewer!);
|
||||
Future render({FFISwapChain? swapChain}) async {
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
swapChain ??= FFISwapChain(Viewer_getSwapChainAt(_viewer!, 0), _viewer!);
|
||||
Viewer_renderRenderThread(_viewer!, view.view, swapChain.swapChain);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<Uint8List> capture() async {
|
||||
final length = this.viewportDimensions.$1.toInt() *
|
||||
this.viewportDimensions.$2.toInt() *
|
||||
4;
|
||||
final out = allocator<Uint8>(length);
|
||||
Future<Uint8List> capture(
|
||||
{FFIView? view,
|
||||
FFISwapChain? swapChain,
|
||||
FFIRenderTarget? renderTarget}) async {
|
||||
view ??= (await getViewAt(0)) as FFIView;
|
||||
final vp = await view.getViewport();
|
||||
final length = vp.width * vp.height * 4;
|
||||
final out = Uint8List(length);
|
||||
|
||||
swapChain ??= FFISwapChain(Viewer_getSwapChainAt(_viewer!, 0), _viewer!);
|
||||
|
||||
await withVoidCallback((cb) {
|
||||
capture_render_thread(_viewer!, out, cb);
|
||||
if (renderTarget != null) {
|
||||
Viewer_captureRenderTargetRenderThread(_viewer!, view!.view,
|
||||
swapChain!.swapChain, renderTarget.renderTarget, out.address, cb);
|
||||
} else {
|
||||
Viewer_captureRenderThread(
|
||||
_viewer!, view!.view, swapChain!.swapChain, out.address, cb);
|
||||
}
|
||||
});
|
||||
final data = Uint8List.fromList(out.asTypedList(length));
|
||||
allocator.free(out);
|
||||
return data;
|
||||
return out;
|
||||
}
|
||||
|
||||
///
|
||||
@@ -246,9 +273,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
await setRendering(false);
|
||||
await clearEntities();
|
||||
await clearLights();
|
||||
print("DESTROYING");
|
||||
destroy_filament_viewer_render_thread(_viewer!);
|
||||
print("DESTROYED");
|
||||
_sceneManager = null;
|
||||
_viewer = null;
|
||||
await _pickResultController.close();
|
||||
@@ -259,7 +284,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
await callback.call();
|
||||
}
|
||||
_onDispose.clear();
|
||||
print("DONE");
|
||||
}
|
||||
|
||||
///
|
||||
@@ -336,7 +360,12 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
Future loadIbl(String lightingPath, {double intensity = 30000}) async {
|
||||
final pathPtr =
|
||||
lightingPath.toNativeUtf8(allocator: allocator).cast<Char>();
|
||||
load_ibl(_viewer!, pathPtr, intensity);
|
||||
|
||||
await withVoidCallback((cb) {
|
||||
Viewer_loadIblRenderThread(_viewer!, pathPtr, intensity, cb);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
///
|
||||
@@ -409,24 +438,24 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
@override
|
||||
Future<ThermionEntity> addDirectLight(DirectLight directLight) async {
|
||||
var entity = add_light(
|
||||
_viewer!,
|
||||
directLight.type.index,
|
||||
directLight.color,
|
||||
directLight.intensity,
|
||||
directLight.position.x,
|
||||
directLight.position.y,
|
||||
directLight.position.z,
|
||||
directLight.direction.x,
|
||||
directLight.direction.y,
|
||||
directLight.direction.z,
|
||||
directLight.falloffRadius,
|
||||
directLight.spotLightConeInner,
|
||||
directLight.spotLightConeOuter,
|
||||
directLight.sunAngularRadius,
|
||||
directLight.sunHaloSize,
|
||||
directLight.sunHaloFallof,
|
||||
directLight.castShadows,
|
||||
);
|
||||
_viewer!,
|
||||
directLight.type.index,
|
||||
directLight.color,
|
||||
directLight.intensity,
|
||||
directLight.position.x,
|
||||
directLight.position.y,
|
||||
directLight.position.z,
|
||||
directLight.direction.x,
|
||||
directLight.direction.y,
|
||||
directLight.direction.z,
|
||||
directLight.falloffRadius,
|
||||
directLight.spotLightConeInner,
|
||||
directLight.spotLightConeOuter,
|
||||
directLight.sunAngularRadius,
|
||||
directLight.sunHaloSize,
|
||||
directLight.sunHaloFallof,
|
||||
directLight.castShadows,
|
||||
);
|
||||
if (entity == _FILAMENT_ASSET_ERROR) {
|
||||
throw Exception("Failed to add light to scene");
|
||||
}
|
||||
@@ -501,6 +530,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
|
||||
var entity = await withIntCallback((callback) => load_glb_render_thread(
|
||||
_sceneManager!, pathPtr, numInstances, keepData, callback));
|
||||
|
||||
allocator.free(pathPtr);
|
||||
if (entity == _FILAMENT_ASSET_ERROR) {
|
||||
throw Exception("An error occurred loading the asset at $path");
|
||||
@@ -521,7 +551,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
int numInstances = 1,
|
||||
bool keepData = false,
|
||||
int priority = 4,
|
||||
int layer = 0}) async {
|
||||
int layer = 0, bool loadResourcesAsync=false}) async {
|
||||
if (unlit) {
|
||||
throw Exception("Not yet implemented");
|
||||
}
|
||||
@@ -531,8 +561,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
|
||||
var entity = await withIntCallback((callback) =>
|
||||
load_glb_from_buffer_render_thread(_sceneManager!, data.address,
|
||||
data.length, numInstances, keepData, priority, layer, callback));
|
||||
SceneManager_loadGlbFromBufferRenderThread(_sceneManager!, data.address,
|
||||
data.length, numInstances, keepData, priority, layer, loadResourcesAsync, callback));
|
||||
|
||||
if (entity == _FILAMENT_ASSET_ERROR) {
|
||||
throw Exception("An error occurred loading GLB from buffer");
|
||||
@@ -560,54 +590,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
return entity;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future panStart(double x, double y) async {
|
||||
grab_begin(_viewer!, x * pixelRatio, y * pixelRatio, true);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future panUpdate(double x, double y) async {
|
||||
grab_update(_viewer!, x * pixelRatio, y * pixelRatio);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future panEnd() async {
|
||||
grab_end(_viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future rotateStart(double x, double y) async {
|
||||
grab_begin(_viewer!, x * pixelRatio, y * pixelRatio, false);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future rotateUpdate(double x, double y) async {
|
||||
grab_update(_viewer!, x * pixelRatio, y * pixelRatio);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future rotateEnd() async {
|
||||
grab_end(_viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -752,7 +734,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
var meshEntity = meshEntities[i];
|
||||
|
||||
if (targetMeshNames?.contains(meshName) == false) {
|
||||
_logger.info("Skipping $meshName, not contained in target");
|
||||
// _logger.info("Skipping $meshName, not contained in target");
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -772,39 +754,24 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
Child meshes: ${meshNames}""");
|
||||
}
|
||||
|
||||
var indices =
|
||||
intersection.map((m) => meshMorphTargets.indexOf(m)).toList();
|
||||
var indices = Uint32List.fromList(
|
||||
intersection.map((m) => meshMorphTargets.indexOf(m)).toList());
|
||||
|
||||
var frameData = animation.extract(morphTargets: intersection);
|
||||
// var frameData = animation.data;
|
||||
var frameData = animation.subset(intersection);
|
||||
|
||||
assert(frameData.length == animation.numFrames * intersection.length);
|
||||
assert(
|
||||
frameData.data.length == animation.numFrames * intersection.length);
|
||||
|
||||
var dataPtr = allocator<Float>(frameData.length);
|
||||
|
||||
// not currently working on WASM :( wasted a lot of time figuring that out as no error is thrown
|
||||
// dataPtr
|
||||
// .asTypedList(frameData.length)
|
||||
// .setRange(0, frameData.length, frameData);
|
||||
for (int i = 0; i < frameData.length; i++) {
|
||||
dataPtr[i] = frameData[i];
|
||||
}
|
||||
|
||||
final idxPtr = allocator<Int>(indices.length);
|
||||
|
||||
for (int i = 0; i < indices.length; i++) {
|
||||
idxPtr[i] = indices[i];
|
||||
}
|
||||
|
||||
var result = set_morph_animation(
|
||||
var result = SceneManager_setMorphAnimation(
|
||||
_sceneManager!,
|
||||
meshEntity,
|
||||
dataPtr,
|
||||
idxPtr,
|
||||
frameData.data.address,
|
||||
indices.address,
|
||||
indices.length,
|
||||
animation.numFrames,
|
||||
animation.frameLengthInMs);
|
||||
allocator.free(dataPtr);
|
||||
allocator.free(idxPtr);
|
||||
|
||||
if (!result) {
|
||||
throw Exception("Failed to set morph animation data for ${meshName}");
|
||||
}
|
||||
@@ -1063,33 +1030,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
});
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future zoomBegin() async {
|
||||
scroll_begin(_viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future zoomUpdate(double x, double y, double z) async {
|
||||
scroll_update(_viewer!, x, y, z);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future zoomEnd() async {
|
||||
scroll_end(_viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -1158,7 +1098,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setMainCamera() async {
|
||||
set_main_camera(_viewer!);
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
Viewer_setMainCamera(_viewer!, view.view);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1179,7 +1120,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
Future<Camera?> getCameraComponent(ThermionEntity cameraEntity) async {
|
||||
var engine = Viewer_getEngine(_viewer!);
|
||||
var camera = Engine_getCameraComponent(engine, cameraEntity);
|
||||
return ThermionFFICamera(camera, engine);
|
||||
return FFICamera(camera, engine);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1189,11 +1130,14 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
Future setCamera(ThermionEntity entity, String? name) async {
|
||||
var cameraNamePtr =
|
||||
name?.toNativeUtf8(allocator: allocator).cast<Char>() ?? nullptr;
|
||||
var result = set_camera(_viewer!, entity, cameraNamePtr);
|
||||
allocator.free(cameraNamePtr);
|
||||
if (!result) {
|
||||
final camera =
|
||||
SceneManager_findCameraByName(_sceneManager!, entity, cameraNamePtr);
|
||||
if (camera == nullptr) {
|
||||
throw Exception("Failed to set camera");
|
||||
}
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
View_setCamera(view.view, camera);
|
||||
allocator.free(cameraNamePtr);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1201,7 +1145,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setToneMapping(ToneMapper mapper) async {
|
||||
set_tone_mapping_render_thread(_viewer!, mapper.index);
|
||||
final view = await getViewAt(0);
|
||||
view.setToneMapper(mapper);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1209,7 +1154,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setPostProcessing(bool enabled) async {
|
||||
set_post_processing_render_thread(_viewer!, enabled);
|
||||
final view = await getViewAt(0) as FFIView;
|
||||
View_setPostProcessing(view.view, enabled);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1217,14 +1163,16 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setShadowsEnabled(bool enabled) async {
|
||||
set_shadows_enabled(_viewer!, enabled);
|
||||
final view = await getViewAt(0) as FFIView;
|
||||
View_setShadowsEnabled(view.view, enabled);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setShadowType(ShadowType shadowType) async {
|
||||
set_shadow_type(_viewer!, shadowType.index);
|
||||
final view = await getViewAt(0) as FFIView;
|
||||
View_setShadowType(view.view, shadowType.index);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1232,7 +1180,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
Future setSoftShadowOptions(
|
||||
double penumbraScale, double penumbraRatioScale) async {
|
||||
set_soft_shadow_options(_viewer!, penumbraScale, penumbraRatioScale);
|
||||
final view = await getViewAt(0) as FFIView;
|
||||
View_setSoftShadowOptions(view.view, penumbraScale, penumbraRatioScale);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1240,7 +1189,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa) async {
|
||||
set_antialiasing(_viewer!, msaa, fxaa, taa);
|
||||
final view = await getViewAt(0) as FFIView;
|
||||
View_setAntiAliasing(view.view, msaa, fxaa, taa);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1248,7 +1198,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setBloom(double bloom) async {
|
||||
set_bloom_render_thread(_viewer!, bloom);
|
||||
final view = await getViewAt(0) as FFIView;
|
||||
View_setBloom(view.view, bloom);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1263,7 +1214,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
///
|
||||
Future<double> getCameraFov(bool horizontal) async {
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
return get_camera_fov(mainCamera.camera, horizontal);
|
||||
}
|
||||
|
||||
@@ -1292,7 +1243,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
|
||||
Future<double> getCameraNear() async {
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
return get_camera_near(mainCamera.camera);
|
||||
}
|
||||
|
||||
@@ -1301,7 +1252,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future<double> getCameraCullingFar() async {
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
return get_camera_culling_far(mainCamera.camera);
|
||||
}
|
||||
|
||||
@@ -1310,7 +1261,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setCameraFocusDistance(double focusDistance) async {
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
set_camera_focus_distance(mainCamera.camera, focusDistance);
|
||||
}
|
||||
|
||||
@@ -1337,7 +1288,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setViewFrustumCulling(bool enabled) async {
|
||||
set_view_frustum_culling(_viewer!, enabled);
|
||||
var view = await getViewAt(0);
|
||||
view.setFrustumCullingEnabled(enabled);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1346,7 +1298,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
@override
|
||||
Future setCameraExposure(
|
||||
double aperture, double shutterSpeed, double sensitivity) async {
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
set_camera_exposure(mainCamera.camera, aperture, shutterSpeed, sensitivity);
|
||||
}
|
||||
|
||||
@@ -1375,25 +1327,11 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setCameraModelMatrix4(Matrix4 modelMatrix) async {
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
final out = matrix4ToDouble4x4(modelMatrix);
|
||||
set_camera_model_matrix(mainCamera.camera, out);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setCameraLensProjection(
|
||||
{double near = kNear,
|
||||
double far = kFar,
|
||||
double? aspect,
|
||||
double focalLength = kFocalLength}) async {
|
||||
aspect ??= viewportDimensions.$1 / viewportDimensions.$2;
|
||||
var mainCamera = get_camera(_viewer!, get_main_camera(_viewer!));
|
||||
Camera_setLensProjection(mainCamera, near, far, aspect, focalLength);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -1480,7 +1418,9 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
Future queuePositionUpdateFromViewportCoords(
|
||||
ThermionEntity entity, double x, double y) async {
|
||||
queue_position_update_from_viewport_coords(_sceneManager!, entity, x, y);
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
queue_position_update_from_viewport_coords(
|
||||
_sceneManager!, view.view, entity, x, y);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1529,46 +1469,28 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
return result.cast<Utf8>().toDartString();
|
||||
}
|
||||
|
||||
void _onPickResult(ThermionEntity entityId, int x, int y) {
|
||||
_pickResultController.add((
|
||||
entity: entityId,
|
||||
x: (x / pixelRatio).toDouble(),
|
||||
y: (viewportDimensions.$2 - y) / pixelRatio
|
||||
));
|
||||
void _onPickResult(
|
||||
ThermionEntity entityId, int x, int y, Pointer<TView> viewPtr) async {
|
||||
final view = FFIView(viewPtr, _viewer!);
|
||||
final viewport = await view.getViewport();
|
||||
|
||||
_pickResultController
|
||||
.add((entity: entityId, x: x.ceil(), y: (viewport.height - y).ceil()));
|
||||
}
|
||||
|
||||
void _onGizmoPickResult(ThermionEntity entityId, int x, int y) {
|
||||
_gizmoPickResultController.add((
|
||||
entity: entityId,
|
||||
x: (x / pixelRatio).toDouble(),
|
||||
y: (viewportDimensions.$2 - y) / pixelRatio
|
||||
));
|
||||
}
|
||||
|
||||
late NativeCallable<Void Function(EntityId entityId, Int x, Int y)>
|
||||
late NativeCallable<Void Function(EntityId entityId, Int x, Int y, Pointer<TView> view)>
|
||||
_onPickResultCallable;
|
||||
late NativeCallable<Void Function(EntityId entityId, Int x, Int y)>
|
||||
_onGizmoPickResultCallable;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
void pick(int x, int y) async {
|
||||
x = (x * pixelRatio).ceil();
|
||||
y = (viewportDimensions.$2 - (y * pixelRatio)).ceil();
|
||||
|
||||
filament_pick(_viewer!, x, y, _onPickResultCallable.nativeFunction);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
void pickGizmo(int x, int y) async {
|
||||
x = (x * pixelRatio).ceil();
|
||||
y = (viewportDimensions.$2 - (y * pixelRatio)).ceil();
|
||||
pick_gizmo(_sceneManager!, x, y, _onGizmoPickResultCallable.nativeFunction);
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
var viewport = await view.getViewport();
|
||||
y = (viewport.height - y).ceil();
|
||||
Viewer_pick(
|
||||
_viewer!, view.view, x, y, _onPickResultCallable.nativeFunction);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1579,7 +1501,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available");
|
||||
}
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
var matrixStruct = get_camera_view_matrix(mainCamera.camera);
|
||||
return double4x4ToMatrix4(matrixStruct);
|
||||
}
|
||||
@@ -1592,7 +1514,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available");
|
||||
}
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
var matrixStruct = get_camera_model_matrix(mainCamera.camera);
|
||||
return double4x4ToMatrix4(matrixStruct);
|
||||
}
|
||||
@@ -1605,7 +1527,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available");
|
||||
}
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
var matrixStruct = get_camera_projection_matrix(mainCamera.camera);
|
||||
return double4x4ToMatrix4(matrixStruct);
|
||||
}
|
||||
@@ -1618,7 +1540,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available");
|
||||
}
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
var matrixStruct = get_camera_culling_projection_matrix(mainCamera.camera);
|
||||
return double4x4ToMatrix4(matrixStruct);
|
||||
}
|
||||
@@ -1649,27 +1571,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
return rotationMatrix;
|
||||
}
|
||||
|
||||
ManipulatorMode _cameraMode = ManipulatorMode.ORBIT;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setCameraManipulatorOptions(
|
||||
{ManipulatorMode? mode,
|
||||
double orbitSpeedX = 0.01,
|
||||
double orbitSpeedY = 0.01,
|
||||
double zoomSpeed = 0.01}) async {
|
||||
if (mode != null) {
|
||||
_cameraMode = mode;
|
||||
}
|
||||
if (_cameraMode != ManipulatorMode.ORBIT) {
|
||||
throw Exception("Manipulator mode $mode not yet implemented");
|
||||
}
|
||||
set_camera_manipulator_options(
|
||||
_viewer!, _cameraMode.index, orbitSpeedX, orbitSpeedX, zoomSpeed);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@@ -1678,7 +1579,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (_viewer == null) {
|
||||
throw Exception("No viewer available");
|
||||
}
|
||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
||||
var mainCamera = await getMainCamera() as FFICamera;
|
||||
var arrayPtr = get_camera_frustum(mainCamera.camera);
|
||||
var doubleList = arrayPtr.asTypedList(24);
|
||||
|
||||
@@ -1747,24 +1648,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
return names;
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setRecording(bool recording) async {
|
||||
set_recording(_viewer!, recording);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future setRecordingOutputDirectory(String outputDir) async {
|
||||
var pathPtr = outputDir.toNativeUtf8(allocator: allocator);
|
||||
set_recording_output_directory(_viewer!, pathPtr.cast<Char>());
|
||||
allocator.free(pathPtr);
|
||||
}
|
||||
|
||||
final _collisions = <ThermionEntity, NativeCallable>{};
|
||||
|
||||
///
|
||||
@@ -1917,7 +1800,8 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future<v64.Aabb2> getViewportBoundingBox(ThermionEntity entityId) async {
|
||||
final result = get_bounding_box(_sceneManager!, entityId);
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
final result = get_bounding_box(_sceneManager!, view.view, entityId);
|
||||
return v64.Aabb2.minMax(v64.Vector2(result.minX, result.minY),
|
||||
v64.Vector2(result.maxX, result.maxY));
|
||||
}
|
||||
@@ -1925,24 +1809,16 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setLayerVisibility(int layer, bool visible) {
|
||||
set_layer_visibility(_sceneManager!, layer, visible);
|
||||
return Future.value();
|
||||
Future setLayerVisibility(int layer, bool visible) async {
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
View_setLayerEnabled(view.view, layer, visible);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setVisibilityLayer(ThermionEntity entity, int layer) {
|
||||
set_visibility_layer(_sceneManager!, entity, layer);
|
||||
return Future.value();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setGizmoVisibility(bool visible) async {
|
||||
set_gizmo_visibility(_sceneManager!, visible);
|
||||
Future setVisibilityLayer(ThermionEntity entity, int layer) async {
|
||||
SceneManager_setVisibilityLayer(_sceneManager!, entity, layer);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -2160,35 +2036,41 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
completer.complete(true);
|
||||
});
|
||||
|
||||
request_frame_render_thread(_viewer!, callback.nativeFunction);
|
||||
Viewer_requestFrameRenderThread(_viewer!, callback.nativeFunction);
|
||||
|
||||
await completer.future;
|
||||
try {
|
||||
await completer.future.timeout(Duration(seconds: 1));
|
||||
} catch (err) {
|
||||
print("WARNING - render call timed out");
|
||||
}
|
||||
}
|
||||
|
||||
Future<Camera> createCamera() async {
|
||||
var cameraPtr = SceneManager_createCamera(_sceneManager!);
|
||||
var engine = Viewer_getEngine(_viewer!);
|
||||
var camera = ThermionFFICamera(cameraPtr, engine);
|
||||
var camera = FFICamera(cameraPtr, engine);
|
||||
return camera;
|
||||
}
|
||||
|
||||
Future destroyCamera(ThermionFFICamera camera) async {
|
||||
Future destroyCamera(FFICamera camera) async {
|
||||
SceneManager_destroyCamera(_sceneManager!, camera.camera);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setActiveCamera(ThermionFFICamera camera) async {
|
||||
SceneManager_setCamera(_sceneManager!, camera.camera);
|
||||
Future setActiveCamera(FFICamera camera) async {
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
View_setCamera(view.view, camera.camera);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<Camera> getActiveCamera() async {
|
||||
final ptr = SceneManager_getActiveCamera(_sceneManager!);
|
||||
return ThermionFFICamera(ptr, Viewer_getEngine(_viewer!));
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
final ptr = View_getCamera(view.view);
|
||||
return FFICamera(ptr, Viewer_getEngine(_viewer!));
|
||||
}
|
||||
|
||||
final _hooks = <Future Function()>[];
|
||||
@@ -2223,7 +2105,24 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (camera == nullptr) {
|
||||
throw Exception("No camera at index $index");
|
||||
}
|
||||
return ThermionFFICamera(camera, Viewer_getEngine(_viewer!));
|
||||
return FFICamera(camera, Viewer_getEngine(_viewer!));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<View> getViewAt(int index) async {
|
||||
var view = Viewer_getViewAt(_viewer!, index);
|
||||
if (view == nullptr) {
|
||||
throw Exception("Failed to get view");
|
||||
}
|
||||
return FFIView(view, _viewer!);
|
||||
}
|
||||
|
||||
@override
|
||||
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);
|
||||
return FFIGizmo(gizmo, this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2254,3 +2153,28 @@ class ThermionFFIMaterialInstance extends MaterialInstance {
|
||||
_pointer, name.toNativeUtf8().cast<Char>(), x, y);
|
||||
}
|
||||
}
|
||||
|
||||
class FFIRenderTarget extends RenderTarget {
|
||||
final Pointer<TRenderTarget> renderTarget;
|
||||
final Pointer<TViewer> viewer;
|
||||
|
||||
FFIRenderTarget(this.renderTarget, this.viewer);
|
||||
|
||||
@override
|
||||
Future destroy() async {
|
||||
Viewer_destroyRenderTarget(viewer, renderTarget);
|
||||
}
|
||||
}
|
||||
|
||||
class FFISwapChain extends SwapChain {
|
||||
final Pointer<TSwapChain> swapChain;
|
||||
final Pointer<TViewer> viewer;
|
||||
|
||||
FFISwapChain(this.swapChain, this.viewer);
|
||||
|
||||
Future destroy() async {
|
||||
await withVoidCallback((callback) {
|
||||
Viewer_destroySwapChainRenderThread(viewer, swapChain, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
library;
|
||||
|
||||
export 'src/thermion_viewer_ffi.dart' show ThermionViewerFFI;
|
||||
export 'src/camera_ffi.dart';
|
||||
|
||||
@@ -2,7 +2,11 @@ import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../thermion_viewer_base.dart';
|
||||
|
||||
enum Projection { Perspective, Orthographic }
|
||||
|
||||
abstract class Camera {
|
||||
Future setProjection(Projection projection, double left, double right,
|
||||
double bottom, double top, double near, double far);
|
||||
Future setProjectionMatrixWithCulling(
|
||||
Matrix4 projectionMatrix, double near, double far);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// "picking" means clicking/tapping on the viewport, and unprojecting the X/Y coordinate to determine whether any renderable entities were present at those coordinates.
|
||||
import '../../viewer.dart';
|
||||
|
||||
typedef FilamentPickResult = ({ThermionEntity entity, double x, double y});
|
||||
typedef ThermionPickResult = FilamentPickResult;
|
||||
typedef FilamentPickResult = ({ThermionEntity entity, int x, int y});
|
||||
typedef PickResult = FilamentPickResult;
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
abstract class RenderTarget {
|
||||
Future destroy();
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
library shared_types;
|
||||
|
||||
export 'swap_chain.dart';
|
||||
export 'view.dart';
|
||||
export 'render_target.dart';
|
||||
export 'camera.dart';
|
||||
export 'material.dart';
|
||||
export 'texture.dart';
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
abstract class SwapChain {
|
||||
Future destroy();
|
||||
}
|
||||
30
thermion_dart/lib/src/viewer/src/shared_types/view.dart
Normal file
30
thermion_dart/lib/src/viewer/src/shared_types/view.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
import 'swap_chain.dart';
|
||||
|
||||
///
|
||||
/// The viewport currently attached to a [View].
|
||||
///
|
||||
/// The dimensions here are guaranteed to be in physical pixels.
|
||||
///
|
||||
class Viewport {
|
||||
final int left;
|
||||
final int bottom;
|
||||
final int width;
|
||||
final int height;
|
||||
|
||||
Viewport(this.left, this.bottom, this.width, this.height);
|
||||
}
|
||||
|
||||
abstract class View {
|
||||
Future<Viewport> getViewport();
|
||||
Future updateViewport(int width, int height);
|
||||
Future setRenderTarget(covariant RenderTarget? renderTarget);
|
||||
Future setCamera(covariant Camera camera);
|
||||
Camera getCamera();
|
||||
Future setPostProcessing(bool enabled);
|
||||
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
|
||||
Future setRenderable(bool renderable, covariant SwapChain swapChain);
|
||||
Future setFrustumCullingEnabled(bool enabled);
|
||||
Future setToneMapper(ToneMapper mapper);
|
||||
Future setBloom(double strength);
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:thermion_dart/src/viewer/src/events.dart';
|
||||
import '../../entities/abstract_gizmo.dart';
|
||||
import 'shared_types/camera.dart';
|
||||
import '../../utils/src/gizmo.dart';
|
||||
import 'shared_types/shared_types.dart';
|
||||
export 'shared_types/shared_types.dart';
|
||||
|
||||
@@ -10,6 +9,8 @@ import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
import 'shared_types/view.dart';
|
||||
|
||||
const double kNear = 0.05;
|
||||
const double kFar = 1000.0;
|
||||
const double kFocalLength = 28.0;
|
||||
@@ -20,16 +21,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future<bool> get initialized;
|
||||
|
||||
///
|
||||
/// The current dimensions of the viewport (in physical pixels).
|
||||
///
|
||||
var viewportDimensions = (0.0, 0.0);
|
||||
|
||||
///
|
||||
/// The current ratio of logical to physical pixels.
|
||||
///
|
||||
late double pixelRatio;
|
||||
|
||||
///
|
||||
/// The result(s) of calling [pick] (see below).
|
||||
/// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick].
|
||||
@@ -37,11 +28,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Stream<FilamentPickResult> get pickResult;
|
||||
|
||||
///
|
||||
/// The result(s) of calling [pickGizmo] (see below).
|
||||
///
|
||||
Stream<FilamentPickResult> get gizmoPickResult;
|
||||
|
||||
///
|
||||
/// A Stream containing entities added/removed to/from to the scene.
|
||||
///
|
||||
@@ -60,7 +46,7 @@ abstract class ThermionViewer {
|
||||
///
|
||||
/// Render a single frame immediately.
|
||||
///
|
||||
Future render();
|
||||
Future render({covariant SwapChain? swapChain});
|
||||
|
||||
///
|
||||
/// Requests a single frame to be rendered. This is only intended to be used internally.
|
||||
@@ -70,7 +56,41 @@ abstract class ThermionViewer {
|
||||
///
|
||||
/// Render a single frame and copy the pixel buffer to [out].
|
||||
///
|
||||
Future<Uint8List> capture();
|
||||
Future<Uint8List> capture(
|
||||
{covariant SwapChain? swapChain,
|
||||
covariant View? view,
|
||||
covariant RenderTarget? renderTarget});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createSwapChain(int handle);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(
|
||||
int width, int height, int textureHandle);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setRenderTarget(covariant RenderTarget renderTarget);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> createView();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> getViewAt(int index);
|
||||
|
||||
///
|
||||
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
|
||||
@@ -196,12 +216,16 @@ abstract class ThermionViewer {
|
||||
/// Specify [numInstances] to create multiple instances (this is more efficient than dynamically instantating at a later time). You can then retrieve the created instances with [getInstances].
|
||||
/// If you want to be able to call [createInstance] at a later time, you must pass true for [keepData].
|
||||
/// If [keepData] is false, the source glTF data will be released and [createInstance] will throw an exception.
|
||||
/// If [loadResourcesAsync] is true, resources (textures, materials, etc) will
|
||||
/// be loaded asynchronously (so expect some material/texture pop-in);
|
||||
///
|
||||
///
|
||||
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data,
|
||||
{int numInstances = 1,
|
||||
bool keepData = false,
|
||||
int priority = 4,
|
||||
int layer = 0});
|
||||
int layer = 0,
|
||||
bool loadResourcesAsync});
|
||||
|
||||
///
|
||||
/// Create a new instance of [entity].
|
||||
@@ -228,36 +252,6 @@ abstract class ThermionViewer {
|
||||
Future<ThermionEntity> loadGltf(String path, String relativeResourcePath,
|
||||
{bool keepData = false});
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panStart(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panUpdate(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future panEnd();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateStart(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateUpdate(double x, double y);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future rotateEnd();
|
||||
|
||||
///
|
||||
/// Set the weights for all morph targets in [entity] to [weights].
|
||||
/// Note that [weights] must contain values for ALL morph targets, but no exception will be thrown if you don't do so (you'll just get incorrect results).
|
||||
@@ -368,7 +362,8 @@ abstract class ThermionViewer {
|
||||
/// Sets multiple transforms (relative to parent) simultaneously for [entity].
|
||||
/// Uses mutex to ensure that transform updates aren't split across frames.
|
||||
///
|
||||
Future queueTransformUpdates(List<ThermionEntity> entities, List<Matrix4> transforms);
|
||||
Future queueTransformUpdates(
|
||||
List<ThermionEntity> entities, List<Matrix4> transforms);
|
||||
|
||||
///
|
||||
/// Updates the bone matrices for [entity] (which must be the ThermionEntity
|
||||
@@ -399,21 +394,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future clearEntities();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomBegin();
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomUpdate(double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomEnd();
|
||||
|
||||
///
|
||||
/// Schedules the glTF animation at [index] in [entity] to start playing on the next frame.
|
||||
///
|
||||
@@ -506,15 +486,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future<double> getCameraCullingFar();
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setCameraLensProjection(
|
||||
{double near = kNear,
|
||||
double far = kFar,
|
||||
double? aspect,
|
||||
double focalLength = kFocalLength});
|
||||
|
||||
///
|
||||
/// Sets the focus distance for the camera.
|
||||
///
|
||||
@@ -714,30 +685,11 @@ abstract class ThermionViewer {
|
||||
///
|
||||
void pick(int x, int y);
|
||||
|
||||
///
|
||||
/// Used to test whether a Gizmo is at the given viewport coordinates.
|
||||
/// Called by `FilamentGestureDetector` on a mouse/finger down event. You probably don't want to call this yourself.
|
||||
/// This is asynchronous and will require 2-3 frames to complete - subscribe to the [gizmoPickResult] stream to receive the results of this method.
|
||||
/// [x] and [y] must be in local logical coordinates (i.e. where 0,0 is at top-left of the ThermionWidget).
|
||||
///
|
||||
void pickGizmo(int x, int y);
|
||||
|
||||
///
|
||||
/// Retrieves the name assigned to the given ThermionEntity (usually corresponds to the glTF mesh name).
|
||||
///
|
||||
String? getNameForEntity(ThermionEntity entity);
|
||||
|
||||
///
|
||||
/// Sets the options for manipulating the camera via the viewport.
|
||||
/// ManipulatorMode.FREE_FLIGHT and ManipulatorMode.MAP are currently unsupported and will throw an exception.
|
||||
///
|
||||
@Deprecated("Use InputHandler instead")
|
||||
Future setCameraManipulatorOptions(
|
||||
{ManipulatorMode mode = ManipulatorMode.ORBIT,
|
||||
double orbitSpeedX = 0.01,
|
||||
double orbitSpeedY = 0.01,
|
||||
double zoomSpeed = 0.01});
|
||||
|
||||
///
|
||||
/// Returns all child entities under [parent].
|
||||
///
|
||||
@@ -757,17 +709,6 @@ abstract class ThermionViewer {
|
||||
Future<List<String>> getChildEntityNames(ThermionEntity entity,
|
||||
{bool renderableOnly = true});
|
||||
|
||||
///
|
||||
/// If [recording] is set to true, each frame the framebuffer/texture will be written to /tmp/output_*.png.
|
||||
/// This will impact performance; handle with care.
|
||||
///
|
||||
Future setRecording(bool recording);
|
||||
|
||||
///
|
||||
/// Sets the output directory where recorded PNGs will be placed.
|
||||
///
|
||||
Future setRecordingOutputDirectory(String outputDirectory);
|
||||
|
||||
///
|
||||
/// An [entity] will only be animatable after an animation component is attached.
|
||||
/// Any calls to [playAnimation]/[setBoneAnimation]/[setMorphAnimation] will have no visual effect until [addAnimationComponent] has been called on the instance.
|
||||
@@ -828,9 +769,9 @@ abstract class ThermionViewer {
|
||||
Future setPriority(ThermionEntity entityId, int priority);
|
||||
|
||||
///
|
||||
/// The gizmo for translating/rotating objects. Only one gizmo is present in the scene.
|
||||
/// The gizmo for translating/rotating objects. Only one gizmo can be active for a given view.
|
||||
///
|
||||
AbstractGizmo? get gizmo;
|
||||
Future<Gizmo> createGizmo(covariant View view);
|
||||
|
||||
///
|
||||
/// Register a callback to be invoked when this viewer is disposed.
|
||||
@@ -854,11 +795,6 @@ abstract class ThermionViewer {
|
||||
///
|
||||
Future setVisibilityLayer(ThermionEntity entity, int layer);
|
||||
|
||||
///
|
||||
/// Show/hide the translation gizmo.
|
||||
///
|
||||
Future setGizmoVisibility(bool visible);
|
||||
|
||||
///
|
||||
/// Renders an outline around [entity] with the given color.
|
||||
///
|
||||
@@ -957,7 +893,7 @@ abstract class ThermionViewer {
|
||||
///
|
||||
///
|
||||
///
|
||||
Future getActiveCamera();
|
||||
Future<Camera> getActiveCamera();
|
||||
|
||||
///
|
||||
///
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:thermion_dart/src/utils/src/gizmo.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/swap_chain.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 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
import '../../entities/abstract_gizmo.dart';
|
||||
import 'events.dart';
|
||||
import 'shared_types/camera.dart';
|
||||
|
||||
@@ -240,10 +241,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement gizmo
|
||||
AbstractGizmo? get gizmo => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future hide(ThermionEntity entity, String? meshName) {
|
||||
// TODO: implement hide
|
||||
@@ -384,12 +381,7 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future render() {
|
||||
// TODO: implement render
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
// TODO: implement rendering
|
||||
bool get rendering => throw UnimplementedError();
|
||||
@@ -723,12 +715,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> capture() {
|
||||
// TODO: implement capture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Aabb2> getBoundingBox(ThermionEntity entity) {
|
||||
// TODO: implement getBoundingBox
|
||||
@@ -907,11 +893,7 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0}) {
|
||||
// TODO: implement loadGlbFromBuffer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future setMaterialPropertyInt(ThermionEntity entity, String propertyName, int materialIndex, int value) {
|
||||
@@ -1007,18 +989,79 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
// TODO: implement getCameraCount
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future getActiveCamera() {
|
||||
// TODO: implement getActiveCamera
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future queueTransformUpdates(List<ThermionEntity> entities, List<Matrix4> transforms) {
|
||||
// TODO: implement queueTransformUpdates
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<RenderTarget> createRenderTarget(int width, int height, int textureHandle) {
|
||||
// TODO: implement createRenderTarget
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setRenderTarget(covariant RenderTarget renderTarget) {
|
||||
// TODO: implement setRenderTarget
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<View> createView() {
|
||||
// TODO: implement createView
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<View> getViewAt(int index) {
|
||||
// TODO: implement getViewAt
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future<Gizmo> createGizmo(covariant View view) {
|
||||
// TODO: implement createGizmo
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height) {
|
||||
// TODO: implement createHeadlessSwapChain
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> capture({covariant SwapChain? swapChain, covariant View? view, covariant RenderTarget? renderTarget}) {
|
||||
// TODO: implement capture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SwapChain> createSwapChain(handle) {
|
||||
// TODO: implement createSwapChain
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future render({covariant SwapChain? swapChain}) {
|
||||
// TODO: implement render
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Camera> getActiveCamera() {
|
||||
// TODO: implement getActiveCamera
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ThermionEntity> loadGlbFromBuffer(Uint8List data, {int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync= false}) {
|
||||
// TODO: implement loadGlbFromBuffer
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../../shared_types/camera.dart';
|
||||
import '../../thermion_viewer_base.dart';
|
||||
|
||||
class ThermionWasmCamera extends Camera {
|
||||
@@ -45,4 +44,34 @@ class ThermionWasmCamera extends Camera {
|
||||
// TODO: implement setModelMatrix
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getCullingFar() {
|
||||
// TODO: implement getCullingFar
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getFocalLength() {
|
||||
// TODO: implement getFocalLength
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getNear() {
|
||||
// TODO: implement getNear
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Matrix4> getViewMatrix() {
|
||||
// TODO: implement getViewMatrix
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setProjection(Projection projection, double left, double right, double bottom, double top, double near, double far) {
|
||||
// TODO: implement setProjection
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,4 +2,4 @@ library filament_dart;
|
||||
|
||||
export 'src/viewer/viewer.dart';
|
||||
export 'src/input/input.dart';
|
||||
export 'src/utils/geometry.dart';
|
||||
export 'src/utils/utils.dart';
|
||||
|
||||
@@ -8,23 +8,27 @@ extern "C"
|
||||
#include <stdint.h>
|
||||
|
||||
typedef int32_t EntityId;
|
||||
typedef int32_t _ManipulatorMode;
|
||||
typedef struct TCamera TCamera;
|
||||
typedef struct TMaterialInstance TMaterialInstance;
|
||||
typedef struct TEngine TEngine;
|
||||
typedef struct TEntityManager TEntityManager;
|
||||
typedef struct TViewer TViewer;
|
||||
typedef struct TSceneManager TSceneManager;
|
||||
|
||||
typedef struct TRenderTarget TRenderTarget;
|
||||
typedef struct TSwapChain TSwapChain;
|
||||
typedef struct TView TView;
|
||||
typedef struct TGizmo TGizmo;
|
||||
typedef struct TScene TScene;
|
||||
|
||||
struct TMaterialKey {
|
||||
bool doubleSided = 1;
|
||||
bool unlit = 1;
|
||||
bool hasVertexColors = 1;
|
||||
bool hasBaseColorTexture = 1;
|
||||
bool hasNormalTexture = 1;
|
||||
bool hasOcclusionTexture = 1;
|
||||
bool hasEmissiveTexture = 1;
|
||||
bool useSpecularGlossiness = 1;
|
||||
bool doubleSided = true;
|
||||
bool unlit = true;
|
||||
bool hasVertexColors = true;
|
||||
bool hasBaseColorTexture = true;
|
||||
bool hasNormalTexture = true;
|
||||
bool hasOcclusionTexture = true;
|
||||
bool hasEmissiveTexture = true;
|
||||
bool useSpecularGlossiness = true;
|
||||
int alphaMode = 4;
|
||||
bool enableDiagnostics = 4;
|
||||
union {
|
||||
@@ -39,42 +43,42 @@ extern "C"
|
||||
};
|
||||
#else
|
||||
struct {
|
||||
bool hasMetallicRoughnessTexture = 1;
|
||||
bool hasMetallicRoughnessTexture = true;
|
||||
uint8_t metallicRoughnessUV = 7;
|
||||
};
|
||||
struct {
|
||||
bool hasSpecularGlossinessTexture = 1;
|
||||
bool hasSpecularGlossinessTexture = true;
|
||||
uint8_t specularGlossinessUV = 7;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
uint8_t baseColorUV;
|
||||
// -- 32 bit boundary --
|
||||
bool hasClearCoatTexture = 1;
|
||||
bool hasClearCoatTexture = true;
|
||||
uint8_t clearCoatUV = 7;
|
||||
bool hasClearCoatRoughnessTexture = 1;
|
||||
bool hasClearCoatRoughnessTexture = true;
|
||||
uint8_t clearCoatRoughnessUV = 7;
|
||||
bool hasClearCoatNormalTexture = 1;
|
||||
bool hasClearCoatNormalTexture = true;
|
||||
uint8_t clearCoatNormalUV = 7;
|
||||
bool hasClearCoat = 1;
|
||||
bool hasTransmission = 1;
|
||||
bool hasClearCoat = true;
|
||||
bool hasTransmission = true;
|
||||
bool hasTextureTransforms = 6;
|
||||
// -- 32 bit boundary --
|
||||
uint8_t emissiveUV;
|
||||
uint8_t aoUV;
|
||||
uint8_t normalUV;
|
||||
bool hasTransmissionTexture = 1;
|
||||
bool hasTransmissionTexture = true;
|
||||
uint8_t transmissionUV = 7;
|
||||
// -- 32 bit boundary --
|
||||
bool hasSheenColorTexture = 1;
|
||||
bool hasSheenColorTexture = true;
|
||||
uint8_t sheenColorUV = 7;
|
||||
bool hasSheenRoughnessTexture = 1;
|
||||
bool hasSheenRoughnessTexture = true;
|
||||
uint8_t sheenRoughnessUV = 7;
|
||||
bool hasVolumeThicknessTexture = 1;
|
||||
bool hasVolumeThicknessTexture = true;
|
||||
uint8_t volumeThicknessUV = 7;
|
||||
bool hasSheen = 1;
|
||||
bool hasIOR = 1;
|
||||
bool hasVolume = 1;
|
||||
bool hasSheen = true;
|
||||
bool hasIOR = true;
|
||||
bool hasVolume = true;
|
||||
} ;
|
||||
typedef struct TMaterialKey TMaterialKey;
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/Frustum.h>
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
using namespace filament;
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include "SceneManager.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
||||
@@ -45,13 +45,6 @@ namespace thermion_filament
|
||||
using namespace gltfio;
|
||||
using namespace camutils;
|
||||
|
||||
enum ToneMapping
|
||||
{
|
||||
ACES,
|
||||
FILMIC,
|
||||
LINEAR
|
||||
};
|
||||
|
||||
class FilamentViewer
|
||||
{
|
||||
|
||||
@@ -61,8 +54,9 @@ namespace thermion_filament
|
||||
FilamentViewer(const void *context, const ResourceLoaderWrapperImpl *const resourceLoaderWrapper, void *const platform = nullptr, const char *uberArchivePath = nullptr);
|
||||
~FilamentViewer();
|
||||
|
||||
void setToneMapping(ToneMapping toneMapping);
|
||||
void setBloom(float strength);
|
||||
View* createView();
|
||||
View* getViewAt(int index);
|
||||
|
||||
void loadSkybox(const char *const skyboxUri);
|
||||
void removeSkybox();
|
||||
|
||||
@@ -74,44 +68,37 @@ namespace thermion_filament
|
||||
void removeEntity(EntityId asset);
|
||||
void clearEntities();
|
||||
|
||||
void updateViewport(uint32_t width, uint32_t height);
|
||||
bool render(
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data);
|
||||
void render(
|
||||
uint64_t frameTimeInNanos
|
||||
);
|
||||
void setFrameInterval(float interval);
|
||||
|
||||
bool setCamera(EntityId asset, const char *nodeName);
|
||||
void setMainCamera();
|
||||
void setMainCamera(View *view);
|
||||
EntityId getMainCamera();
|
||||
Camera* getCamera(EntityId entity);
|
||||
|
||||
float getCameraFov(bool horizontal);
|
||||
void setCameraFov(double fovDegrees, bool horizontal);
|
||||
|
||||
void createSwapChain(const void *surface, uint32_t width, uint32_t height);
|
||||
void destroySwapChain();
|
||||
SwapChain* createSwapChain(const void *surface);
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height);
|
||||
void destroySwapChain(SwapChain* swapChain);
|
||||
|
||||
void createRenderTarget(intptr_t textureId, uint32_t width, uint32_t height);
|
||||
RenderTarget* createRenderTarget(intptr_t textureId, uint32_t width, uint32_t height);
|
||||
void destroyRenderTarget(RenderTarget* renderTarget);
|
||||
|
||||
Renderer *getRenderer();
|
||||
|
||||
std::map<SwapChain*, std::vector<View*>> _renderable;
|
||||
|
||||
void setRenderable(View* view, SwapChain* swapChain, bool renderable);
|
||||
|
||||
void setBackgroundColor(const float r, const float g, const float b, const float a);
|
||||
void setBackgroundImage(const char *resourcePath, bool fillHeight);
|
||||
void setBackgroundImage(const char *resourcePath, bool fillHeight, uint32_t width, uint32_t height);
|
||||
void clearBackgroundImage();
|
||||
void setBackgroundImagePosition(float x, float y, bool clamp);
|
||||
|
||||
void setViewFrustumCulling(bool enabled);
|
||||
|
||||
void setCameraManipulatorOptions(filament::camutils::Mode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||
void grabBegin(float x, float y, bool pan);
|
||||
void grabUpdate(float x, float y);
|
||||
void grabEnd();
|
||||
void scrollBegin();
|
||||
void scrollUpdate(float x, float y, float delta);
|
||||
void scrollEnd();
|
||||
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
||||
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));
|
||||
Engine* getEngine() {
|
||||
return _engine;
|
||||
}
|
||||
@@ -137,44 +124,38 @@ namespace thermion_filament
|
||||
void setLightDirection(EntityId entityId, float x, float y, float z);
|
||||
void removeLight(EntityId entityId);
|
||||
void clearLights();
|
||||
void setPostProcessing(bool enabled);
|
||||
|
||||
void setRecording(bool recording);
|
||||
void setRecordingOutputDirectory(const char *path);
|
||||
void capture(uint8_t *out, bool useFence, void (*onComplete)());
|
||||
|
||||
void setAntiAliasing(bool msaaEnabled, bool fxaaEnabled, bool taaEnabled);
|
||||
void setDepthOfField();
|
||||
void setShadowsEnabled(bool enabled);
|
||||
void setShadowType(ShadowType shadowType);
|
||||
void setSoftShadowOptions( float penumbraScale, float penumbraRatioScale);
|
||||
void capture(View* view, uint8_t *out, bool useFence, SwapChain* swapChain, void (*onComplete)());
|
||||
void capture(View* view, uint8_t *out, bool useFence, SwapChain* swapChain, RenderTarget* renderTarget, void (*onComplete)());
|
||||
|
||||
SceneManager *const getSceneManager()
|
||||
{
|
||||
return (SceneManager *const)_sceneManager;
|
||||
}
|
||||
|
||||
SwapChain* getSwapChainAt(int index) {
|
||||
if(index < _swapChains.size()) {
|
||||
return _swapChains[index];
|
||||
}
|
||||
Log("Error: index %d is greater than available swapchains", index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void unprojectTexture(EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight);
|
||||
|
||||
private:
|
||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||
void* _context = nullptr;
|
||||
Scene *_scene = nullptr;
|
||||
|
||||
View *_view = nullptr;
|
||||
|
||||
Engine *_engine = nullptr;
|
||||
thermion_filament::ThreadPool *_tp = nullptr;
|
||||
thermion::ThreadPool *_tp = nullptr;
|
||||
Renderer *_renderer = nullptr;
|
||||
RenderTarget *_rt = nullptr;
|
||||
Texture *_rtColor = nullptr;
|
||||
Texture *_rtDepth = nullptr;
|
||||
|
||||
SwapChain *_swapChain = nullptr;
|
||||
|
||||
SceneManager *_sceneManager = nullptr;
|
||||
std::vector<RenderTarget*> _renderTargets;
|
||||
std::vector<SwapChain*> _swapChains;
|
||||
std::vector<View*> _views;
|
||||
|
||||
std::mutex mtx; // mutex to ensure thread safety when removing assets
|
||||
std::mutex _renderMutex; // mutex to ensure thread safety when removing assets
|
||||
|
||||
std::vector<utils::Entity> _lights;
|
||||
Texture *_skyboxTexture = nullptr;
|
||||
@@ -187,16 +168,6 @@ namespace thermion_filament
|
||||
// Camera properties
|
||||
Camera *_mainCamera = nullptr; // the default camera added to every scene. If you want the *active* camera, access via View.
|
||||
|
||||
Manipulator<double> *_manipulator = nullptr;
|
||||
filament::camutils::Mode _manipulatorMode = filament::camutils::Mode::ORBIT;
|
||||
double _orbitSpeedX = 0.01;
|
||||
double _orbitSpeedY = 0.01;
|
||||
double _zoomSpeed = 0.01;
|
||||
|
||||
void _createManipulator();
|
||||
|
||||
ColorGrading *colorGrading = nullptr;
|
||||
|
||||
// background image properties
|
||||
uint32_t _imageHeight = 0;
|
||||
uint32_t _imageWidth = 0;
|
||||
@@ -215,12 +186,10 @@ namespace thermion_filament
|
||||
void savePng(void *data, size_t size, int frameNumber);
|
||||
void createBackgroundImage();
|
||||
|
||||
time_point_t _recordingStartTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
time_point_t _fpsCounterStartTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
bool _recording = false;
|
||||
std::string _recordingOutputDirectory = std::string("/tmp");
|
||||
std::mutex _recordingMutex;
|
||||
|
||||
std::mutex _imageMutex;
|
||||
double _cumulativeAnimationUpdateTime = 0;
|
||||
int _frameCount = 0;
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
@@ -29,38 +29,13 @@ using namespace utils;
|
||||
class Gizmo {
|
||||
|
||||
enum Axis { X, Y, Z};
|
||||
|
||||
class PickCallbackHandler {
|
||||
public:
|
||||
PickCallbackHandler(Gizmo* gizmo, void (*callback)(EntityId entityId, int x, int y)) : _gizmo(gizmo), _callback(callback) {};
|
||||
void handle(filament::View::PickingQueryResult const &result) {
|
||||
auto x = static_cast<int32_t>(result.fragCoords.x);
|
||||
auto y= static_cast<int32_t>(result.fragCoords.y);
|
||||
for(int i = 0; i < 7; i++) {
|
||||
if(_gizmo->_entities[i] == result.renderable) {
|
||||
if(i < 4) {
|
||||
return;
|
||||
}
|
||||
_gizmo->highlight(_gizmo->_entities[i - 4]);
|
||||
_callback(Entity::smuggle(_gizmo->_entities[i - 4]), x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_gizmo->unhighlight();
|
||||
_callback(0, x, y);
|
||||
delete(this);
|
||||
}
|
||||
|
||||
private:
|
||||
Gizmo* _gizmo;
|
||||
void (*_callback)(EntityId entityId, int x, int y);
|
||||
|
||||
};
|
||||
|
||||
|
||||
public:
|
||||
Gizmo(Engine& engine, View *view, Scene *scene);
|
||||
Gizmo(Engine *engine, View *view, Scene *scene);
|
||||
~Gizmo();
|
||||
|
||||
typedef void (*PickCallback)(EntityId entityId, uint32_t x, uint32_t y, View *view);
|
||||
|
||||
Entity x() {
|
||||
return _entities[0];
|
||||
};
|
||||
@@ -73,26 +48,49 @@ class Gizmo {
|
||||
Entity center() {
|
||||
return _entities[3];
|
||||
};
|
||||
View* view() {
|
||||
return _view;
|
||||
}
|
||||
|
||||
bool isActive() {
|
||||
return _isActive;
|
||||
}
|
||||
|
||||
void pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y));
|
||||
void pick(uint32_t x, uint32_t y, PickCallback callback);
|
||||
bool isGizmoEntity(Entity entity);
|
||||
void setVisibility(bool visible);
|
||||
|
||||
private:
|
||||
|
||||
class PickCallbackHandler {
|
||||
public:
|
||||
PickCallbackHandler(Gizmo* gizmo, PickCallback callback) : _gizmo(gizmo), _callback(callback) {};
|
||||
void handle(filament::View::PickingQueryResult const &result) {
|
||||
auto x = static_cast<int32_t>(result.fragCoords.x);
|
||||
auto y= static_cast<int32_t>(result.fragCoords.y);
|
||||
for(int i = 0; i < 7; i++) {
|
||||
if(_gizmo->_entities[i] == result.renderable) {
|
||||
if(i < 4) {
|
||||
return;
|
||||
}
|
||||
_gizmo->highlight(_gizmo->_entities[i - 4]);
|
||||
_callback(Entity::smuggle(_gizmo->_entities[i - 4]), x, y, _gizmo->_view);
|
||||
return;
|
||||
}
|
||||
}
|
||||
_gizmo->unhighlight();
|
||||
_callback(0, x, y, _gizmo->_view);
|
||||
delete(this);
|
||||
}
|
||||
|
||||
private:
|
||||
Gizmo* _gizmo;
|
||||
PickCallback _callback;
|
||||
|
||||
};
|
||||
void createTransparentRectangles();
|
||||
void highlight(Entity entity);
|
||||
void unhighlight();
|
||||
Engine &_engine;
|
||||
View *_view;
|
||||
Engine *_engine;
|
||||
Scene *_scene;
|
||||
filament::Camera *_camera;
|
||||
View *_view;
|
||||
utils::Entity _entities[7] = { utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity(), utils::Entity() };
|
||||
Material* _material;
|
||||
MaterialInstance* _materialInstances[7];
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "material/gizmo.h"
|
||||
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament;
|
||||
using namespace utils;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
using namespace std::chrono_literals;
|
||||
#endif
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
struct ResourceLoaderWrapperImpl : public ResourceLoaderWrapper
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
#include <filament/InstanceBuffer.h>
|
||||
#include <utils/NameComponentManager.h>
|
||||
|
||||
#include "material/gizmo.h"
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "Gizmo.hpp"
|
||||
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "GridOverlay.hpp"
|
||||
#include "ResourceBuffer.hpp"
|
||||
@@ -32,7 +30,7 @@
|
||||
#include "tsl/robin_map.h"
|
||||
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
typedef int32_t EntityId;
|
||||
|
||||
@@ -46,7 +44,7 @@ namespace thermion_filament
|
||||
class SceneManager
|
||||
{
|
||||
public:
|
||||
SceneManager(View* view,
|
||||
SceneManager(
|
||||
const ResourceLoaderWrapperImpl *const loader,
|
||||
Engine *engine,
|
||||
Scene *scene,
|
||||
@@ -94,7 +92,7 @@ namespace thermion_filament
|
||||
/// @return an Entity representing the FilamentAsset associated with the loaded FilamentAsset.
|
||||
///
|
||||
EntityId loadGlb(const char *uri, int numInstances, bool keepData);
|
||||
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0);
|
||||
EntityId loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances = 1, bool keepData = false, int priority = 4, int layer = 0, bool loadResourcesAsync = false);
|
||||
EntityId createInstance(EntityId entityId);
|
||||
|
||||
void remove(EntityId entity);
|
||||
@@ -111,9 +109,9 @@ namespace thermion_filament
|
||||
void setRotation(EntityId e, float rads, float x, float y, float z, float w);
|
||||
|
||||
void queueTransformUpdates(EntityId* entities, math::mat4* transforms, int numEntities);
|
||||
|
||||
void queueRelativePositionUpdateWorldAxis(EntityId entity, float viewportCoordX, float viewportCoordY, float x, float y, float z);
|
||||
void queueRelativePositionUpdateFromViewportVector(EntityId entityId, float viewportCoordX, float viewportCoordY);
|
||||
void queueRelativePositionUpdateFromViewportVector(View* view, EntityId entityId, float viewportCoordX, float viewportCoordY);
|
||||
|
||||
const utils::Entity *getCameraEntities(EntityId e);
|
||||
size_t getCameraEntityCount(EntityId e);
|
||||
const utils::Entity *getLightEntities(EntityId e) noexcept;
|
||||
@@ -127,7 +125,7 @@ namespace thermion_filament
|
||||
bool setMorphAnimationBuffer(
|
||||
EntityId entityId,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
@@ -231,12 +229,7 @@ namespace thermion_filament
|
||||
/// @param out a pointer large enough to store four floats (the min/max coordinates of the bounding box)
|
||||
/// @return
|
||||
///
|
||||
Aabb2 getBoundingBox(EntityId entity);
|
||||
|
||||
///
|
||||
/// Toggles the visibility of the given layer.
|
||||
///
|
||||
void setLayerVisibility(SceneManager::LAYERS layer, bool enabled);
|
||||
Aabb2 getBoundingBox(View* view, EntityId entity);
|
||||
|
||||
///
|
||||
/// Creates an entity with the specified geometry/material/normals and adds to the scene.
|
||||
@@ -258,8 +251,6 @@ namespace thermion_filament
|
||||
|
||||
friend class FilamentViewer;
|
||||
|
||||
Gizmo* gizmo = nullptr;
|
||||
|
||||
gltfio::MaterialProvider * const unlitMaterialProvider() {
|
||||
return _unlitMaterialProvider;
|
||||
}
|
||||
@@ -272,10 +263,6 @@ namespace thermion_filament
|
||||
return _geometry[entityId].get();
|
||||
}
|
||||
|
||||
Scene* const getScene() {
|
||||
return _scene;
|
||||
}
|
||||
|
||||
bool isGltfAsset(EntityId entity) {
|
||||
return getAssetByEntityId(entity) != nullptr;
|
||||
}
|
||||
@@ -308,20 +295,21 @@ namespace thermion_filament
|
||||
|
||||
void destroyCamera(Camera* camera);
|
||||
|
||||
void setCamera(Camera* camera);
|
||||
|
||||
size_t getCameraCount();
|
||||
|
||||
Camera* getCameraAt(size_t index);
|
||||
|
||||
Camera* getActiveCamera();
|
||||
bool isGizmoEntity(utils::Entity entity);
|
||||
|
||||
Scene* getScene() {
|
||||
return _scene;
|
||||
}
|
||||
|
||||
private:
|
||||
gltfio::AssetLoader *_assetLoader = nullptr;
|
||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||
Engine *_engine = nullptr;
|
||||
Scene *_scene = nullptr;
|
||||
View* _view = nullptr;
|
||||
Camera* _mainCamera;
|
||||
|
||||
gltfio::MaterialProvider *_ubershaderProvider = nullptr;
|
||||
@@ -331,6 +319,7 @@ namespace thermion_filament
|
||||
gltfio::TextureProvider *_ktxDecoder = nullptr;
|
||||
std::mutex _mutex;
|
||||
std::mutex _stencilMutex;
|
||||
std::vector<MaterialInstance*> _materialInstances;
|
||||
|
||||
utils::NameComponentManager *_ncm;
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
|
||||
//
|
||||
|
||||
50
thermion_dart/native/include/TCamera.h
Normal file
50
thermion_dart/native/include/TCamera.h
Normal file
@@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
enum Projection {
|
||||
Perspective,
|
||||
Orthographic
|
||||
};
|
||||
|
||||
// Camera methods
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera* camera);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera);
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float focusDistance);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* camera, double4x4 projectionMatrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera* camera, double4x4 modelMatrix);
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera* camera);
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setProjection(TCamera *const tCamera, Projection projection, double left, double right,
|
||||
double bottom, double top,
|
||||
double near, double far);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
19
thermion_dart/native/include/TGizmo.h
Normal file
19
thermion_dart/native/include/TGizmo.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TGizmo.h"
|
||||
|
||||
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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
49
thermion_dart/native/include/TView.h
Normal file
49
thermion_dart/native/include/TView.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
struct TViewport {
|
||||
int32_t left;
|
||||
int32_t bottom;
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
};
|
||||
typedef struct TViewport TViewport;
|
||||
|
||||
enum ToneMapping
|
||||
{
|
||||
ACES,
|
||||
FILMIC,
|
||||
LINEAR
|
||||
};
|
||||
|
||||
// View
|
||||
EMSCRIPTEN_KEEPALIVE TViewport View_getViewport(TView *view);
|
||||
EMSCRIPTEN_KEEPALIVE void View_updateViewport(TView *view, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setRenderTarget(TView *view, TRenderTarget *renderTarget);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setFrustumCullingEnabled(TView *view, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void View_updateViewport(TView* tView, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setRenderTarget(TView* tView, TRenderTarget* tRenderTarget);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setFrustumCullingEnabled(TView* tView, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setPostProcessing(TView* tView, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setShadowsEnabled(TView* tView, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setShadowType(TView* tView, int shadowType);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setSoftShadowOptions(TView* tView, float penumbraScale, float penumbraRatioScale);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setBloom(TView* tView, float strength);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setToneMapping(TView* tView, TEngine* tEngine, ToneMapping toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setAntiAliasing(TView *tView, bool msaa, bool fxaa, bool taa);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setLayerEnabled(TView *tView, int layer, bool visible);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setCamera(TView *tView, TCamera *tCamera);
|
||||
EMSCRIPTEN_KEEPALIVE TScene* View_getScene(TView *tView);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* View_getCamera(TView *tView);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
27
thermion_dart/native/include/ThermionDartAPIUtils.h
Normal file
27
thermion_dart/native/include/ThermionDartAPIUtils.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#include <math/mat4.h>
|
||||
#include "APIBoundaryTypes.h"
|
||||
|
||||
namespace thermion {
|
||||
|
||||
// Helper function to convert filament::math::mat4 to double4x4
|
||||
static double4x4 convert_mat4_to_double4x4(const filament::math::mat4 &mat)
|
||||
{
|
||||
return double4x4{
|
||||
{mat[0][0], mat[0][1], mat[0][2], mat[0][3]},
|
||||
{mat[1][0], mat[1][1], mat[1][2], mat[1][3]},
|
||||
{mat[2][0], mat[2][1], mat[2][2], mat[2][3]},
|
||||
{mat[3][0], mat[3][1], mat[3][2], mat[3][3]},
|
||||
};
|
||||
}
|
||||
|
||||
// Helper function to convert double4x4 to filament::math::mat4
|
||||
static filament::math::mat4 convert_double4x4_to_mat4(const double4x4 &d_mat)
|
||||
{
|
||||
return filament::math::mat4{
|
||||
filament::math::float4{float(d_mat.col1[0]), float(d_mat.col1[1]), float(d_mat.col1[2]), float(d_mat.col1[3])},
|
||||
filament::math::float4{float(d_mat.col2[0]), float(d_mat.col2[1]), float(d_mat.col2[2]), float(d_mat.col2[3])},
|
||||
filament::math::float4{float(d_mat.col3[0]), float(d_mat.col3[1]), float(d_mat.col3[2]), float(d_mat.col3[3])},
|
||||
filament::math::float4{float(d_mat.col4[0]), float(d_mat.col4[1]), float(d_mat.col4[2]), float(d_mat.col4[3])}};
|
||||
}
|
||||
}
|
||||
@@ -48,30 +48,58 @@
|
||||
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "ThermionDartAPIUtils.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *create_filament_viewer(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget* Viewer_createRenderTarget(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *viewer, TRenderTarget* tRenderTarget);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *viewer, const void *const window);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *viewer, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *viewer, TSwapChain* swapChain);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_render(
|
||||
TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *viewer,
|
||||
TView *view,
|
||||
TSwapChain *swapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *viewer,
|
||||
TView *view,
|
||||
TSwapChain *swapChain,
|
||||
TRenderTarget *renderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void));
|
||||
EMSCRIPTEN_KEEPALIVE TView* Viewer_createView(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TView* Viewer_getViewAt(TViewer *viewer, int index);
|
||||
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));
|
||||
|
||||
// Engine
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine* tEngine, EntityId entity, double4x4 transform);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(TViewer *viewer, int toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom(TViewer *viewer, float strength);
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath);
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl(TViewer *viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer);
|
||||
@@ -99,35 +127,15 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_position(TViewer *viewer, EntityId light, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void set_light_direction(TViewer *viewer, EntityId light, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(TSceneManager *sceneManager, const void *const data, size_t length, bool keepData, int priority, int layer);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_gltf(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId create_instance(TSceneManager *sceneManager, EntityId id);
|
||||
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out);
|
||||
EMSCRIPTEN_KEEPALIVE void set_main_camera(TViewer *viewer);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_camera(TViewer *viewer, EntityId entity, const char *nodeName);
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE bool render(
|
||||
TViewer *viewer,
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data);
|
||||
EMSCRIPTEN_KEEPALIVE void capture(
|
||||
TViewer *viewer,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void));
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(TViewer *viewer, const void *const window, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(TViewer *viewer);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(TViewer *viewer, float interval);
|
||||
EMSCRIPTEN_KEEPALIVE void update_viewport(TViewer *viewer, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_begin(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_update(TViewer *viewer, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_end(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_begin(TViewer *viewer, float x, float y, bool pan);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_update(TViewer *viewer, float x, float y);
|
||||
EMSCRIPTEN_KEEPALIVE void grab_end(TViewer *viewer);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId entity,
|
||||
@@ -139,14 +147,6 @@ extern "C"
|
||||
EntityId entity,
|
||||
const float *const morphData,
|
||||
int numWeights);
|
||||
EMSCRIPTEN_KEEPALIVE bool set_morph_animation(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId entity,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(TSceneManager *sceneManager, TMaterialKey materialConfig);
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_unlit_material_instance(TSceneManager *sceneManager);
|
||||
@@ -199,6 +199,19 @@ extern "C"
|
||||
|
||||
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);
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer);
|
||||
EMSCRIPTEN_KEEPALIVE TScene* SceneManager_getScene(TSceneManager *tSceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId SceneManager_loadGlbFromBuffer(TSceneManager *sceneManager, const uint8_t *const, size_t length, bool keepData, int priority, int layer, bool loadResourcesAsync);
|
||||
EMSCRIPTEN_KEEPALIVE bool SceneManager_setMorphAnimation(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId entity,
|
||||
const float *const morphData,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs);
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(TSceneManager *sceneManager, EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE void get_morph_target_name(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index);
|
||||
@@ -209,70 +222,31 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE void transform_to_unit_cube(TSceneManager *sceneManager, EntityId asset);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(TSceneManager *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, EntityId entity, float viewportX, float viewportY);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *view, EntityId entity, float viewportX, float viewportY);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_position(TSceneManager *sceneManager, EntityId entity, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void set_rotation(TSceneManager *sceneManager, EntityId entity, float rads, float x, float y, float z, float w);
|
||||
EMSCRIPTEN_KEEPALIVE void set_scale(TSceneManager *sceneManager, EntityId entity, float scale);
|
||||
|
||||
// Camera methods
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const camera);
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera* camera);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera);
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera);
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float focusDistance);
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(TViewer *viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* camera, double4x4 projectionMatrix, double near, double far);
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera* camera, double4x4 modelMatrix);
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera* camera);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *engine, EntityId entity);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEntityManager *Engine_getEntityManager(TEngine *engine);
|
||||
|
||||
// SceneManager
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_createCamera(TSceneManager *sceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *sceneManager, TCamera* camera);
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setCamera(TSceneManager *sceneManager, TCamera* camera);
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *sceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraAt(TSceneManager *sceneManager, size_t index);
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getActiveCamera(TSceneManager *sceneManager);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int hide_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
|
||||
EMSCRIPTEN_KEEPALIVE int reveal_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(TViewer *viewer, bool enabled);
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadow_type(TViewer *viewer, int shadowType);
|
||||
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(TViewer *viewer, float penumbraScale, float penumbraRatioScale);
|
||||
EMSCRIPTEN_KEEPALIVE void set_antialiasing(TViewer *viewer, bool msaa, bool fxaa, bool taa);
|
||||
EMSCRIPTEN_KEEPALIVE void filament_pick(TViewer *viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(TSceneManager *sceneManager, const EntityId entityId);
|
||||
EMSCRIPTEN_KEEPALIVE EntityId find_child_entity_by_name(TSceneManager *sceneManager, const EntityId parent, const char *name);
|
||||
EMSCRIPTEN_KEEPALIVE int get_entity_count(TSceneManager *sceneManager, const EntityId target, bool renderableOnly);
|
||||
EMSCRIPTEN_KEEPALIVE void get_entities(TSceneManager *sceneManager, const EntityId target, bool renderableOnly, EntityId *out);
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_entity_name_at(TSceneManager *sceneManager, const EntityId target, int index, bool renderableOnly);
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording(TViewer *viewer, bool recording);
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(TViewer *viewer, const char *outputDirectory);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy();
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
|
||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
||||
@@ -298,13 +272,11 @@ extern "C"
|
||||
EMSCRIPTEN_KEEPALIVE void set_parent(TSceneManager *sceneManager, EntityId child, EntityId parent, bool preserveScaling);
|
||||
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_priority(TSceneManager *sceneManager, EntityId entityId, int priority);
|
||||
EMSCRIPTEN_KEEPALIVE void get_gizmo(TSceneManager *sceneManager, EntityId *out);
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
|
||||
EMSCRIPTEN_KEEPALIVE void set_layer_visibility(TSceneManager *sceneManager, int layer, bool visible);
|
||||
EMSCRIPTEN_KEEPALIVE void set_visibility_layer(TSceneManager *sceneManager, EntityId entity, int layer);
|
||||
EMSCRIPTEN_KEEPALIVE void pick_gizmo(TSceneManager *sceneManager, int x, int y, void (*callback)(EntityId entityId, int x, int y));
|
||||
EMSCRIPTEN_KEEPALIVE void set_gizmo_visibility(TSceneManager *sceneManager, bool visible);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *view, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *view, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(TSceneManager *sceneManager, EntityId entity, float r, float g, float b);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_stencil_highlight(TSceneManager *sceneManager, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_float(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, float value);
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
#define _DART_FILAMENT_FFI_API_H
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TView.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
@@ -17,7 +19,7 @@ extern "C"
|
||||
typedef int32_t EntityId;
|
||||
typedef void (*FilamentRenderCallback)(void *const owner);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_render_thread(
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
|
||||
void *const context,
|
||||
void *const platform,
|
||||
const char *uberArchivePath,
|
||||
@@ -25,32 +27,38 @@ extern "C"
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
void *const renderCallbackOwner,
|
||||
void (*callback)(TViewer *viewer));
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(TViewer *viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(TViewer *viewer, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(TViewer *viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer, void *const surface, void (*onComplete)(TSwapChain*));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, uint32_t width, uint32_t height, void (*onComplete)(TSwapChain*));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain* swapChain, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, uint8_t* out, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, TRenderTarget* renderTarget, uint8_t* out, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void(*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom);
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void render_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void capture_render_thread(TViewer *viewer, uint8_t* out, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
||||
|
||||
FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
||||
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void(*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(TViewer *viewer, void(*onComplete)());
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(TViewer *viewer, int toneMapping);
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(TViewer *viewer, float strength);
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer);
|
||||
|
||||
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 load_glb_render_thread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(TSceneManager *sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, void (*callback)(EntityId));
|
||||
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(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));
|
||||
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer, EntityId asset, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(TViewer *viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights_render_thread(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
@@ -99,6 +107,7 @@ extern "C"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DART_FILAMENT_FFI_API_H
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#ifndef _THREADPOOL_HPP
|
||||
#define _THREADPOOL_HPP
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
class ThreadPool {
|
||||
std::vector<std::thread> pool;
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
#include "CustomGeometry.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
class UnprojectTexture {
|
||||
public:
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include <utils/NameComponentManager.h>
|
||||
|
||||
template class std::vector<float>;
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
using namespace filament;
|
||||
using namespace filament::gltfio;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "gltfio/FilamentInstance.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
typedef void(*CollisionCallback)(int32_t entityId1, int32_t entityId2) ;
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
// Generated by Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
|
||||
#ifndef SWIFT_MODULE_SWIFT_H
|
||||
#define SWIFT_MODULE_SWIFT_H
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgcc-compat"
|
||||
|
||||
#if !defined(__has_include)
|
||||
# define __has_include(x) 0
|
||||
#endif
|
||||
#if !defined(__has_attribute)
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
#if !defined(__has_feature)
|
||||
# define __has_feature(x) 0
|
||||
#endif
|
||||
#if !defined(__has_warning)
|
||||
# define __has_warning(x) 0
|
||||
#endif
|
||||
|
||||
#if __has_include(<swift/objc-prologue.h>)
|
||||
# include <swift/objc-prologue.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wauto-import"
|
||||
#if defined(__OBJC__)
|
||||
#include <Foundation/Foundation.h>
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <cstdbool>
|
||||
#include <cstring>
|
||||
#include <stdlib.h>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#else
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
#if defined(__arm64e__) && __has_include(<ptrauth.h>)
|
||||
# include <ptrauth.h>
|
||||
#else
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wreserved-macro-identifier"
|
||||
# ifndef __ptrauth_swift_value_witness_function_pointer
|
||||
# define __ptrauth_swift_value_witness_function_pointer(x)
|
||||
# endif
|
||||
# ifndef __ptrauth_swift_class_method_pointer
|
||||
# define __ptrauth_swift_class_method_pointer(x)
|
||||
# endif
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_TYPEDEFS)
|
||||
# define SWIFT_TYPEDEFS 1
|
||||
# if __has_include(<uchar.h>)
|
||||
# include <uchar.h>
|
||||
# elif !defined(__cplusplus)
|
||||
typedef uint_least16_t char16_t;
|
||||
typedef uint_least32_t char32_t;
|
||||
# endif
|
||||
typedef float swift_float2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef float swift_float3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef float swift_float4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef double swift_double2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef double swift_double3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef double swift_double4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef int swift_int2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef int swift_int3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef int swift_int4 __attribute__((__ext_vector_type__(4)));
|
||||
typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2)));
|
||||
typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3)));
|
||||
typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4)));
|
||||
#endif
|
||||
|
||||
#if !defined(SWIFT_PASTE)
|
||||
# define SWIFT_PASTE_HELPER(x, y) x##y
|
||||
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
|
||||
#endif
|
||||
#if !defined(SWIFT_METATYPE)
|
||||
# define SWIFT_METATYPE(X) Class
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_PROPERTY)
|
||||
# if __has_feature(objc_class_property)
|
||||
# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__
|
||||
# else
|
||||
# define SWIFT_CLASS_PROPERTY(...)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_RUNTIME_NAME)
|
||||
# if __has_attribute(objc_runtime_name)
|
||||
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
|
||||
# else
|
||||
# define SWIFT_RUNTIME_NAME(X)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_COMPILE_NAME)
|
||||
# if __has_attribute(swift_name)
|
||||
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
|
||||
# else
|
||||
# define SWIFT_COMPILE_NAME(X)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_METHOD_FAMILY)
|
||||
# if __has_attribute(objc_method_family)
|
||||
# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X)))
|
||||
# else
|
||||
# define SWIFT_METHOD_FAMILY(X)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_NOESCAPE)
|
||||
# if __has_attribute(noescape)
|
||||
# define SWIFT_NOESCAPE __attribute__((noescape))
|
||||
# else
|
||||
# define SWIFT_NOESCAPE
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_RELEASES_ARGUMENT)
|
||||
# if __has_attribute(ns_consumed)
|
||||
# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed))
|
||||
# else
|
||||
# define SWIFT_RELEASES_ARGUMENT
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_WARN_UNUSED_RESULT)
|
||||
# if __has_attribute(warn_unused_result)
|
||||
# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
|
||||
# else
|
||||
# define SWIFT_WARN_UNUSED_RESULT
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_NORETURN)
|
||||
# if __has_attribute(noreturn)
|
||||
# define SWIFT_NORETURN __attribute__((noreturn))
|
||||
# else
|
||||
# define SWIFT_NORETURN
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS_EXTRA)
|
||||
# define SWIFT_CLASS_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_PROTOCOL_EXTRA)
|
||||
# define SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_EXTRA)
|
||||
# define SWIFT_ENUM_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_CLASS)
|
||||
# if __has_attribute(objc_subclassing_restricted)
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# else
|
||||
# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_RESILIENT_CLASS)
|
||||
# if __has_attribute(objc_class_stub)
|
||||
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub))
|
||||
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME)
|
||||
# else
|
||||
# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME)
|
||||
# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_PROTOCOL)
|
||||
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
|
||||
#endif
|
||||
#if !defined(SWIFT_EXTENSION)
|
||||
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
|
||||
#endif
|
||||
#if !defined(OBJC_DESIGNATED_INITIALIZER)
|
||||
# if __has_attribute(objc_designated_initializer)
|
||||
# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
# else
|
||||
# define OBJC_DESIGNATED_INITIALIZER
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM_ATTR)
|
||||
# if __has_attribute(enum_extensibility)
|
||||
# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility)))
|
||||
# else
|
||||
# define SWIFT_ENUM_ATTR(_extensibility)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_ENUM)
|
||||
# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
|
||||
# if __has_feature(generalized_swift_name)
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type
|
||||
# else
|
||||
# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility)
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE)
|
||||
# define SWIFT_UNAVAILABLE __attribute__((unavailable))
|
||||
#endif
|
||||
#if !defined(SWIFT_UNAVAILABLE_MSG)
|
||||
# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg)))
|
||||
#endif
|
||||
#if !defined(SWIFT_AVAILABILITY)
|
||||
# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__)))
|
||||
#endif
|
||||
#if !defined(SWIFT_WEAK_IMPORT)
|
||||
# define SWIFT_WEAK_IMPORT __attribute__((weak_import))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED)
|
||||
# define SWIFT_DEPRECATED __attribute__((deprecated))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED_MSG)
|
||||
# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__)))
|
||||
#endif
|
||||
#if !defined(SWIFT_DEPRECATED_OBJC)
|
||||
# if __has_feature(attribute_diagnose_if_objc)
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning")))
|
||||
# else
|
||||
# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg)
|
||||
# endif
|
||||
#endif
|
||||
#if defined(__OBJC__)
|
||||
#if !defined(IBSegueAction)
|
||||
# define IBSegueAction
|
||||
#endif
|
||||
#endif
|
||||
#if !defined(SWIFT_EXTERN)
|
||||
# if defined(__cplusplus)
|
||||
# define SWIFT_EXTERN extern "C"
|
||||
# else
|
||||
# define SWIFT_EXTERN extern
|
||||
# endif
|
||||
#endif
|
||||
#if !defined(SWIFT_CALL)
|
||||
# define SWIFT_CALL __attribute__((swiftcall))
|
||||
#endif
|
||||
#if !defined(SWIFT_INDIRECT_RESULT)
|
||||
# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result))
|
||||
#endif
|
||||
#if !defined(SWIFT_CONTEXT)
|
||||
# define SWIFT_CONTEXT __attribute__((swift_context))
|
||||
#endif
|
||||
#if !defined(SWIFT_ERROR_RESULT)
|
||||
# define SWIFT_ERROR_RESULT __attribute__((swift_error_result))
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
# define SWIFT_NOEXCEPT noexcept
|
||||
#else
|
||||
# define SWIFT_NOEXCEPT
|
||||
#endif
|
||||
#if !defined(SWIFT_C_INLINE_THUNK)
|
||||
# if __has_attribute(always_inline)
|
||||
# if __has_attribute(nodebug)
|
||||
# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug))
|
||||
# else
|
||||
# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline))
|
||||
# endif
|
||||
# else
|
||||
# define SWIFT_C_INLINE_THUNK inline
|
||||
# endif
|
||||
#endif
|
||||
#if defined(_WIN32)
|
||||
#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
|
||||
# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL)
|
||||
# define SWIFT_IMPORT_STDLIB_SYMBOL
|
||||
#endif
|
||||
#endif
|
||||
#if defined(__OBJC__)
|
||||
#if __has_feature(objc_modules)
|
||||
#if __has_warning("-Watimport-in-framework-header")
|
||||
#pragma clang diagnostic ignored "-Watimport-in-framework-header"
|
||||
#endif
|
||||
@import CoreVideo;
|
||||
@import ObjectiveC;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
|
||||
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
|
||||
#if __has_warning("-Wpragma-clang-attribute")
|
||||
# pragma clang diagnostic ignored "-Wpragma-clang-attribute"
|
||||
#endif
|
||||
#pragma clang diagnostic ignored "-Wunknown-pragmas"
|
||||
#pragma clang diagnostic ignored "-Wnullability"
|
||||
#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension"
|
||||
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# pragma push_macro("any")
|
||||
# undef any
|
||||
# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="swift_module",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol))
|
||||
# pragma pop_macro("any")
|
||||
#endif
|
||||
|
||||
#if defined(__OBJC__)
|
||||
@protocol MTLDevice;
|
||||
@protocol MTLTexture;
|
||||
@class NSData;
|
||||
|
||||
SWIFT_CLASS("_TtC12swift_module20ThermionTextureSwift")
|
||||
@interface ThermionTextureSwift : NSObject
|
||||
@property (nonatomic) CVMetalTextureCacheRef _Nullable cvMetalTextureCache;
|
||||
@property (nonatomic, strong) id <MTLDevice> _Nullable metalDevice;
|
||||
@property (nonatomic) CVMetalTextureRef _Nullable cvMetalTexture;
|
||||
@property (nonatomic, strong) id <MTLTexture> _Nullable metalTexture;
|
||||
@property (nonatomic) NSInteger metalTextureAddress;
|
||||
- (nonnull instancetype)init OBJC_DESIGNATED_INITIALIZER;
|
||||
- (nonnull instancetype)initWithWidth:(int64_t)width height:(int64_t)height OBJC_DESIGNATED_INITIALIZER;
|
||||
- (void)destroyTexture;
|
||||
- (void)fillColor;
|
||||
- (NSData * _Nullable)getTextureBytes SWIFT_WARN_UNUSED_RESULT;
|
||||
@end
|
||||
|
||||
#endif
|
||||
#if __has_attribute(external_source_symbol)
|
||||
# pragma clang attribute pop
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <math/norm.h>
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
|
||||
class FileMaterialProvider : public filament::gltfio::MaterialProvider {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
class UnlitMaterialProvider : public filament::gltfio::MaterialProvider {
|
||||
private:
|
||||
@@ -63,6 +63,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace thermion_filament
|
||||
} // namespace thermion
|
||||
|
||||
#endif // UNLIT_MATERIAL_PROVIDER_HPP
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:02859acdfdc2227784553f616bf55cd34e5931413b21c6fea7aaf79d2aa56af3
|
||||
size 10694
|
||||
@@ -1,3 +0,0 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:1d0fb1cf7f63c52b5a82a25d2038a1b2d6b9bc9f54491d73345900f58b0b8087
|
||||
size 224
|
||||
Binary file not shown.
@@ -11,7 +11,7 @@
|
||||
#include "Log.hpp"
|
||||
#include "CustomGeometry.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,25 +10,21 @@
|
||||
#include "material/gizmo.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||
Gizmo::Gizmo(Engine *engine, View *view, Scene* scene) : _engine(engine), _view(view), _scene(scene)
|
||||
{
|
||||
|
||||
_scene = scene;
|
||||
_view = view;
|
||||
_camera = &(_view->getCamera());
|
||||
|
||||
|
||||
auto &entityManager = EntityManager::get();
|
||||
|
||||
auto &transformManager = engine.getTransformManager();
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
|
||||
_material =
|
||||
Material::Builder()
|
||||
.package(GIZMO_GIZMO_DATA, GIZMO_GIZMO_SIZE)
|
||||
.build(engine);
|
||||
.build(*_engine);
|
||||
|
||||
// First, create the black cube at the center
|
||||
// The axes widgets will be parented to this entity
|
||||
@@ -62,13 +58,13 @@ Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(engine);
|
||||
.build(*engine);
|
||||
|
||||
centerCubeVb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
centerCubeVb->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(centerCubeVertices, 8 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(engine);
|
||||
centerCubeIb->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||
auto centerCubeIb = IndexBuffer::Builder().indexCount(36).bufferType(IndexBuffer::IndexType::USHORT).build(*engine);
|
||||
centerCubeIb->setBuffer(*engine, IndexBuffer::BufferDescriptor(
|
||||
centerCubeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
@@ -81,7 +77,7 @@ Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||
.priority(7)
|
||||
.geometry(0, RenderableManager::PrimitiveType::TRIANGLES, centerCubeVb, centerCubeIb, 0, 36)
|
||||
.culling(false)
|
||||
.build(engine, _entities[3]);
|
||||
.build(*engine, _entities[3]);
|
||||
|
||||
auto cubeTransformInstance = transformManager.getInstance(_entities[3]);
|
||||
math::mat4f cubeTransform;
|
||||
@@ -128,13 +124,13 @@ Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||
.vertexCount(13)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(engine);
|
||||
.build(*engine);
|
||||
|
||||
vb->setBufferAt(engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
vb->setBufferAt(*engine, 0, VertexBuffer::BufferDescriptor(vertices, 13 * sizeof(filament::math::float3), [](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<float *>(buffer); }));
|
||||
|
||||
auto ib = IndexBuffer::Builder().indexCount(54).bufferType(IndexBuffer::IndexType::USHORT).build(engine);
|
||||
ib->setBuffer(engine, IndexBuffer::BufferDescriptor(
|
||||
auto ib = IndexBuffer::Builder().indexCount(54).bufferType(IndexBuffer::IndexType::USHORT).build(*engine);
|
||||
ib->setBuffer(*engine, IndexBuffer::BufferDescriptor(
|
||||
indices, 54 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *)
|
||||
{ delete[] static_cast<uint16_t *>(buffer); }));
|
||||
@@ -176,7 +172,7 @@ Gizmo::Gizmo(Engine &engine, View* view, Scene* scene) : _engine(engine)
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(engine, _entities[i]);
|
||||
.build(*engine, _entities[i]);
|
||||
|
||||
|
||||
auto instance = transformManager.getInstance(_entities[i]);
|
||||
@@ -194,21 +190,21 @@ Gizmo::~Gizmo() {
|
||||
_scene->removeEntities(_entities, 7);
|
||||
|
||||
for(int i = 0; i < 7; i++) {
|
||||
_engine.destroy(_entities[i]);
|
||||
_engine->destroy(_entities[i]);
|
||||
}
|
||||
|
||||
for(int i = 0; i < 7; i++) {
|
||||
_engine.destroy(_materialInstances[i]);
|
||||
_engine->destroy(_materialInstances[i]);
|
||||
}
|
||||
|
||||
_engine.destroy(_material);
|
||||
_engine->destroy(_material);
|
||||
|
||||
}
|
||||
|
||||
void Gizmo::createTransparentRectangles()
|
||||
{
|
||||
auto &entityManager = EntityManager::get();
|
||||
auto &transformManager = _engine.getTransformManager();
|
||||
auto &transformManager = _engine->getTransformManager();
|
||||
|
||||
float volumeWidth = 0.2f;
|
||||
float volumeLength = 1.2f;
|
||||
@@ -238,9 +234,9 @@ void Gizmo::createTransparentRectangles()
|
||||
.vertexCount(8)
|
||||
.bufferCount(1)
|
||||
.attribute(VertexAttribute::POSITION, 0, VertexBuffer::AttributeType::FLOAT3)
|
||||
.build(_engine);
|
||||
.build(*_engine);
|
||||
|
||||
volumeVb->setBufferAt(_engine, 0, VertexBuffer::BufferDescriptor(
|
||||
volumeVb->setBufferAt(*_engine, 0, VertexBuffer::BufferDescriptor(
|
||||
volumeVertices, 8 * sizeof(filament::math::float3),
|
||||
[](void *buffer, size_t size, void *) { delete[] static_cast<float *>(buffer); }
|
||||
));
|
||||
@@ -248,9 +244,9 @@ void Gizmo::createTransparentRectangles()
|
||||
auto volumeIb = IndexBuffer::Builder()
|
||||
.indexCount(36)
|
||||
.bufferType(IndexBuffer::IndexType::USHORT)
|
||||
.build(_engine);
|
||||
.build(*_engine);
|
||||
|
||||
volumeIb->setBuffer(_engine, IndexBuffer::BufferDescriptor(
|
||||
volumeIb->setBuffer(*_engine, IndexBuffer::BufferDescriptor(
|
||||
volumeIndices, 36 * sizeof(uint16_t),
|
||||
[](void *buffer, size_t size, void *) { delete[] static_cast<uint16_t *>(buffer); }
|
||||
));
|
||||
@@ -284,7 +280,7 @@ void Gizmo::createTransparentRectangles()
|
||||
.culling(false)
|
||||
.receiveShadows(false)
|
||||
.castShadows(false)
|
||||
.build(_engine, _entities[i]);
|
||||
.build(*_engine, _entities[i]);
|
||||
|
||||
auto instance = transformManager.getInstance(_entities[i]);
|
||||
transformManager.setTransform(instance, transform);
|
||||
@@ -295,7 +291,7 @@ void Gizmo::createTransparentRectangles()
|
||||
}
|
||||
|
||||
void Gizmo::highlight(Entity entity) {
|
||||
auto &rm = _engine.getRenderableManager();
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
auto renderableInstance = rm.getInstance(entity);
|
||||
auto materialInstance = rm.getMaterialInstanceAt(renderableInstance, 0);
|
||||
|
||||
@@ -315,7 +311,7 @@ void Gizmo::highlight(Entity entity) {
|
||||
}
|
||||
|
||||
void Gizmo::unhighlight() {
|
||||
auto &rm = _engine.getRenderableManager();
|
||||
auto &rm = _engine->getRenderableManager();
|
||||
|
||||
for(int i = 0; i < 3; i++) {
|
||||
auto renderableInstance = rm.getInstance(_entities[i]);
|
||||
@@ -326,7 +322,7 @@ void Gizmo::unhighlight() {
|
||||
}
|
||||
}
|
||||
|
||||
void Gizmo::pick(uint32_t x, uint32_t y, void (*callback)(EntityId entityId, int x, int y))
|
||||
void Gizmo::pick(uint32_t x, uint32_t y, PickCallback callback)
|
||||
{
|
||||
auto handler = new Gizmo::PickCallbackHandler(this, callback);
|
||||
_view->pick(x, y, [=](filament::View::PickingQueryResult const &result) {
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
#ifdef _WIN32
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <cmath>
|
||||
#endif
|
||||
|
||||
#include "GridOverlay.hpp"
|
||||
|
||||
#include <filament/Engine.h>
|
||||
@@ -11,7 +16,7 @@
|
||||
#include "SceneManager.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
using namespace filament::gltfio;
|
||||
|
||||
@@ -194,4 +199,4 @@ void GridOverlay::destroy()
|
||||
_engine.destroy(_gridEntity);
|
||||
}
|
||||
|
||||
} // namespace thermion_filament
|
||||
} // namespace thermion
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "SceneManager.hpp"
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
SceneManager::HighlightOverlay::HighlightOverlay(
|
||||
|
||||
@@ -38,7 +38,7 @@ extern "C"
|
||||
#include "material/image.h"
|
||||
}
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
using namespace std::chrono;
|
||||
@@ -48,13 +48,12 @@ namespace thermion_filament
|
||||
using namespace filament::gltfio;
|
||||
using std::unique_ptr;
|
||||
|
||||
SceneManager::SceneManager(View *view,
|
||||
const ResourceLoaderWrapperImpl *const resourceLoaderWrapper,
|
||||
SceneManager::SceneManager(const ResourceLoaderWrapperImpl *const resourceLoaderWrapper,
|
||||
Engine *engine,
|
||||
Scene *scene,
|
||||
const char *uberArchivePath,
|
||||
Camera *mainCamera)
|
||||
: _view(view),
|
||||
:
|
||||
_resourceLoaderWrapper(resourceLoaderWrapper),
|
||||
_engine(engine),
|
||||
_scene(scene),
|
||||
@@ -99,28 +98,22 @@ namespace thermion_filament
|
||||
_collisionComponentManager = new CollisionComponentManager(tm);
|
||||
_animationComponentManager = new AnimationComponentManager(tm, _engine->getRenderableManager());
|
||||
|
||||
gizmo = new Gizmo(*_engine, _view, _scene);
|
||||
_gridOverlay = new GridOverlay(*_engine);
|
||||
|
||||
_scene->addEntity(_gridOverlay->sphere());
|
||||
_scene->addEntity(_gridOverlay->grid());
|
||||
|
||||
_view->setLayerEnabled(SceneManager::LAYERS::DEFAULT_ASSETS, true);
|
||||
_view->setLayerEnabled(SceneManager::LAYERS::BACKGROUND, true); // skybox + image
|
||||
_view->setLayerEnabled(SceneManager::LAYERS::OVERLAY, false); // world grid + gizmo
|
||||
}
|
||||
|
||||
SceneManager::~SceneManager()
|
||||
{
|
||||
_view->setScene(nullptr);
|
||||
_view->setCamera(nullptr);
|
||||
for(auto camera : _cameras) {
|
||||
auto entity = camera->getEntity();
|
||||
_engine->destroyCameraComponent(entity);
|
||||
_engine->getEntityManager().destroy(entity);
|
||||
}
|
||||
_cameras.clear();
|
||||
delete gizmo;
|
||||
|
||||
_gridOverlay->destroy();
|
||||
destroyAll();
|
||||
|
||||
@@ -138,6 +131,10 @@ namespace thermion_filament
|
||||
AssetLoader::destroy(&_assetLoader);
|
||||
}
|
||||
|
||||
bool SceneManager::isGizmoEntity(Entity entity) {
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
int SceneManager::getInstanceCount(EntityId entityId)
|
||||
{
|
||||
auto *asset = getAssetByEntityId(entityId);
|
||||
@@ -260,7 +257,7 @@ namespace thermion_filament
|
||||
|
||||
}
|
||||
|
||||
EntityId SceneManager::loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances, bool keepData, int priority, int layer)
|
||||
EntityId SceneManager::loadGlbFromBuffer(const uint8_t *data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync)
|
||||
{
|
||||
|
||||
FilamentAsset *asset = nullptr;
|
||||
@@ -307,10 +304,18 @@ namespace thermion_filament
|
||||
_gltfResourceLoader->asyncUpdateLoad();
|
||||
}
|
||||
#else
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
return 0;
|
||||
if(loadResourcesAsync) {
|
||||
if (!_gltfResourceLoader->asyncBeginLoad(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
if (!_gltfResourceLoader->loadResources(asset))
|
||||
{
|
||||
Log("Unknown error loading glb asset");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -534,13 +539,18 @@ namespace thermion_filament
|
||||
asset.second->getLightEntityCount());
|
||||
_assetLoader->destroyAsset(asset.second);
|
||||
}
|
||||
for(auto* texture : _textures) {
|
||||
for(auto *texture : _textures) {
|
||||
_engine->destroy(texture);
|
||||
}
|
||||
|
||||
for(auto *materialInstance : _materialInstances) {
|
||||
_engine->destroy(materialInstance);
|
||||
}
|
||||
|
||||
// TODO - free geometry?
|
||||
_textures.clear();
|
||||
_assets.clear();
|
||||
_materialInstances.clear();
|
||||
}
|
||||
|
||||
FilamentInstance *SceneManager::getInstanceByEntityId(EntityId entityId)
|
||||
@@ -804,7 +814,7 @@ namespace thermion_filament
|
||||
bool SceneManager::setMorphAnimationBuffer(
|
||||
EntityId entityId,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs)
|
||||
@@ -1894,11 +1904,11 @@ namespace thermion_filament
|
||||
tm.setTransform(transformInstance, newTransform);
|
||||
}
|
||||
|
||||
void SceneManager::queueRelativePositionUpdateFromViewportVector(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();
|
||||
const auto &vp = _view->getViewport();
|
||||
const auto &camera = view->getCamera();
|
||||
const auto &vp = view->getViewport();
|
||||
|
||||
// Convert viewport coordinates to NDC space
|
||||
float ndcX = (2.0f * viewportCoordX) / vp.width - 1.0f;
|
||||
@@ -2170,10 +2180,10 @@ namespace thermion_filament
|
||||
rm.setPriority(renderableInstance, priority);
|
||||
}
|
||||
|
||||
Aabb2 SceneManager::getBoundingBox(EntityId entityId)
|
||||
Aabb2 SceneManager::getBoundingBox(View *view, EntityId entityId)
|
||||
{
|
||||
const auto &camera = _view->getCamera();
|
||||
const auto &viewport = _view->getViewport();
|
||||
const auto &camera = view->getCamera();
|
||||
const auto &viewport = view->getViewport();
|
||||
|
||||
auto &tcm = _engine->getTransformManager();
|
||||
auto &rcm = _engine->getRenderableManager();
|
||||
@@ -2242,11 +2252,6 @@ namespace thermion_filament
|
||||
return Aabb2{minX, minY, maxX, maxY};
|
||||
}
|
||||
|
||||
void SceneManager::setLayerVisibility(LAYERS layer, bool enabled)
|
||||
{
|
||||
_view->setLayerEnabled(layer, enabled);
|
||||
}
|
||||
|
||||
void SceneManager::removeStencilHighlight(EntityId entityId)
|
||||
{
|
||||
std::lock_guard lock(_stencilMutex);
|
||||
@@ -2464,6 +2469,7 @@ EntityId SceneManager::createGeometry(
|
||||
}
|
||||
materialInstance->setParameter("baseColorFactor", RgbaType::sRGB, filament::math::float4{1.0f, 0.0f, 1.0f, 1.0f});
|
||||
materialInstance->setParameter("baseColorIndex", 0);
|
||||
_materialInstances.push_back(materialInstance);
|
||||
return materialInstance;
|
||||
}
|
||||
|
||||
@@ -2471,6 +2477,7 @@ EntityId SceneManager::createGeometry(
|
||||
UvMap uvmap;
|
||||
auto instance = _unlitMaterialProvider->createMaterialInstance(nullptr, &uvmap);
|
||||
instance->setParameter("uvScale", filament::math::float2 { 1.0f, 1.0f });
|
||||
_materialInstances.push_back(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -2491,10 +2498,6 @@ EntityId SceneManager::createGeometry(
|
||||
}
|
||||
}
|
||||
|
||||
void SceneManager::setCamera(Camera* camera) {
|
||||
_view->setCamera(camera);
|
||||
}
|
||||
|
||||
size_t SceneManager::getCameraCount() {
|
||||
return _cameras.size() + 1;
|
||||
}
|
||||
@@ -2508,11 +2511,6 @@ EntityId SceneManager::createGeometry(
|
||||
}
|
||||
return _cameras[index-1];
|
||||
}
|
||||
|
||||
Camera* SceneManager::getActiveCamera() {
|
||||
auto& camera = _view->getCamera();
|
||||
return &camera;
|
||||
}
|
||||
|
||||
|
||||
} // namespace thermion_filament
|
||||
} // namespace thermion
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace thermion_filament {
|
||||
namespace thermion {
|
||||
|
||||
class StreamBufferAdapter : public std::streambuf
|
||||
{
|
||||
|
||||
84
thermion_dart/native/src/TCamera.cpp
Normal file
84
thermion_dart/native/src/TCamera.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
#include <filament/View.h>
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/ToneMapper.h>
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Camera.h>
|
||||
#include <utils/Entity.h>
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TCamera.h"
|
||||
#include "ThermionDartAPIUtils.h"
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera *tCamera, double4x4 projectionMatrix, double near, double far)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
camera->setCustomProjection(convert_double4x4_to_mat4(projectionMatrix), near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera *tCamera)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
return convert_mat4_to_double4x4(camera->getModelMatrix());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const tCamera)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
return convert_mat4_to_double4x4(camera->getViewMatrix());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera *tCamera)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
return utils::Entity::smuggle(camera->getEntity());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const tCamera)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
return camera->getFocalLength() * 1000.0;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *const tCamera)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
return camera->getNear();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *const tCamera)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
return camera->getCullingFar();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setProjection(TCamera *const tCamera, Projection projection, double left, double right,
|
||||
double bottom, double top,
|
||||
double near, double far)
|
||||
{
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
filament::Camera::Projection filamentProjection;
|
||||
switch(projection) {
|
||||
case Projection::Orthographic:
|
||||
filamentProjection = filament::Camera::Projection::ORTHO;
|
||||
case Projection::Perspective:
|
||||
filamentProjection = filament::Camera::Projection::PERSPECTIVE;
|
||||
}
|
||||
camera->setProjection(filamentProjection, left, right, bottom, top, near, far);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
40
thermion_dart/native/src/TGizmo.cpp
Normal file
40
thermion_dart/native/src/TGizmo.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <filament/View.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Scene.h>
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TGizmo.h"
|
||||
#include "Gizmo.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion {
|
||||
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);
|
||||
gizmo->pick(x, y, reinterpret_cast<Gizmo::PickCallback>(callback));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Gizmo_setVisibility(TGizmo *tGizmo, bool visible) {
|
||||
auto *gizmo = reinterpret_cast<Gizmo*>(tGizmo);
|
||||
gizmo->setVisibility(visible);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
162
thermion_dart/native/src/TView.cpp
Normal file
162
thermion_dart/native/src/TView.cpp
Normal file
@@ -0,0 +1,162 @@
|
||||
#include <filament/View.h>
|
||||
#include <filament/Viewport.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/ToneMapper.h>
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Camera.h>
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TView.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion {
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewport View_getViewport(TView *tView)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
auto & vp = view->getViewport();
|
||||
TViewport tvp;
|
||||
tvp.left = vp.left;
|
||||
tvp.bottom = vp.bottom;
|
||||
tvp.width = vp.width;
|
||||
tvp.height = vp.height;
|
||||
return tvp;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_updateViewport(TView *tView, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setViewport({0, 0, width, height});
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setRenderTarget(TView *tView, TRenderTarget *tRenderTarget)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
view->setRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setFrustumCullingEnabled(TView *tView, bool enabled)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setFrustumCullingEnabled(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setPostProcessing(TView *tView, bool enabled)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setPostProcessingEnabled(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setShadowsEnabled(TView *tView, bool enabled)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setShadowingEnabled(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setShadowType(TView *tView, int shadowType)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setShadowType((ShadowType)shadowType);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setSoftShadowOptions(TView *tView, float penumbraScale, float penumbraRatioScale)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
SoftShadowOptions opts;
|
||||
opts.penumbraRatioScale = penumbraRatioScale;
|
||||
opts.penumbraScale = penumbraScale;
|
||||
view->setSoftShadowOptions(opts);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setBloom(TView *tView, float strength)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
#ifndef __EMSCRIPTEN__
|
||||
decltype(view->getBloomOptions()) opts;
|
||||
opts.enabled = true;
|
||||
opts.strength = strength;
|
||||
view->setBloomOptions(opts);
|
||||
#endif
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setToneMapping(TView *tView, TEngine *tEngine, ToneMapping toneMapping)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
auto engine = reinterpret_cast<Engine *>(tEngine);
|
||||
|
||||
ToneMapper *tm;
|
||||
switch (toneMapping)
|
||||
{
|
||||
case ToneMapping::ACES:
|
||||
Log("Setting tone mapping to ACES");
|
||||
tm = new ACESToneMapper();
|
||||
break;
|
||||
case ToneMapping::LINEAR:
|
||||
Log("Setting tone mapping to Linear");
|
||||
tm = new LinearToneMapper();
|
||||
break;
|
||||
case ToneMapping::FILMIC:
|
||||
Log("Setting tone mapping to Filmic");
|
||||
tm = new FilmicToneMapper();
|
||||
break;
|
||||
default:
|
||||
Log("ERROR: Unsupported tone mapping");
|
||||
return;
|
||||
}
|
||||
auto newColorGrading = ColorGrading::Builder().toneMapper(tm).build(*engine);
|
||||
auto oldColorGrading = view->getColorGrading();
|
||||
view->setColorGrading(newColorGrading);
|
||||
|
||||
if (oldColorGrading)
|
||||
{
|
||||
engine->destroy(oldColorGrading);
|
||||
}
|
||||
delete tm;
|
||||
}
|
||||
|
||||
void View_setAntiAliasing(TView *tView, bool msaa, bool fxaa, bool taa)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
View::MultiSampleAntiAliasingOptions multiSampleAntiAliasingOptions;
|
||||
multiSampleAntiAliasingOptions.enabled = msaa;
|
||||
|
||||
view->setMultiSampleAntiAliasingOptions(multiSampleAntiAliasingOptions);
|
||||
TemporalAntiAliasingOptions taaOpts;
|
||||
taaOpts.enabled = taa;
|
||||
view->setTemporalAntiAliasingOptions(taaOpts);
|
||||
view->setAntiAliasing(fxaa ? AntiAliasing::FXAA : AntiAliasing::NONE);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setLayerEnabled(TView* tView, int layer, bool enabled) {
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
view->setLayerEnabled(layer, enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setCamera(TView *tView, TCamera *tCamera) {
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
view->setCamera(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TScene* View_getScene(TView* tView) {
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
return reinterpret_cast<TScene*>(view->getScene());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* View_getCamera(TView *tView) {
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
return reinterpret_cast<TCamera*>(&(view->getCamera()));
|
||||
}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,14 +1,7 @@
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
#include "ThermionWin32.h"
|
||||
#endif
|
||||
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "filament/LightManager.h"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
@@ -16,49 +9,51 @@
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
using namespace thermion_filament;
|
||||
#include "filament/LightManager.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
|
||||
// Helper function to convert filament::math::mat4 to double4x4
|
||||
static double4x4 convert_mat4_to_double4x4(const filament::math::mat4 &mat)
|
||||
{
|
||||
return double4x4{
|
||||
{mat[0][0], mat[0][1], mat[0][2], mat[0][3]},
|
||||
{mat[1][0], mat[1][1], mat[1][2], mat[1][3]},
|
||||
{mat[2][0], mat[2][1], mat[2][2], mat[2][3]},
|
||||
{mat[3][0], mat[3][1], mat[3][2], mat[3][3]},
|
||||
};
|
||||
}
|
||||
|
||||
// Helper function to convert double4x4 to filament::math::mat4
|
||||
static filament::math::mat4 convert_double4x4_to_mat4(const double4x4 &d_mat)
|
||||
{
|
||||
return filament::math::mat4{
|
||||
filament::math::float4{float(d_mat.col1[0]), float(d_mat.col1[1]), float(d_mat.col1[2]), float(d_mat.col1[3])},
|
||||
filament::math::float4{float(d_mat.col2[0]), float(d_mat.col2[1]), float(d_mat.col2[2]), float(d_mat.col2[3])},
|
||||
filament::math::float4{float(d_mat.col3[0]), float(d_mat.col3[1]), float(d_mat.col3[2]), float(d_mat.col3[3])},
|
||||
filament::math::float4{float(d_mat.col4[0]), float(d_mat.col4[1]), float(d_mat.col4[2]), float(d_mat.col4[3])}};
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *create_filament_viewer(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||
{
|
||||
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
|
||||
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
||||
return reinterpret_cast<TViewer*>(viewer);
|
||||
return reinterpret_cast<TViewer *>(viewer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer) {
|
||||
auto* engine = reinterpret_cast<FilamentViewer*>(viewer)->getEngine();
|
||||
return reinterpret_cast<TEngine*>(engine);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target(TViewer *viewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createRenderTarget(texture, width, height);
|
||||
auto *engine = reinterpret_cast<FilamentViewer *>(viewer)->getEngine();
|
||||
return reinterpret_cast<TEngine *>(engine);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget *Viewer_createRenderTarget(TViewer *tViewer, intptr_t texture, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = viewer->createRenderTarget(texture, width, height);
|
||||
return reinterpret_cast<TRenderTarget *>(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget *tRenderTarget)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
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))
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer(TViewer *viewer)
|
||||
@@ -78,23 +73,14 @@ extern "C"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight);
|
||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp);
|
||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping(TViewer *viewer, int toneMapping)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setToneMapping((ToneMapping)toneMapping);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom(TViewer *viewer, float strength)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBloom(strength);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath)
|
||||
{
|
||||
@@ -106,7 +92,7 @@ extern "C"
|
||||
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl(TViewer *viewer, const char *iblPath, float intensity)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||
}
|
||||
@@ -182,7 +168,7 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->loadGlb(assetPath, numInstances, keepData);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId load_glb_from_buffer(TSceneManager *sceneManager, const void *const data, size_t length, bool keepData, int priority, int layer)
|
||||
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);
|
||||
}
|
||||
@@ -207,9 +193,11 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->loadGltf(assetPath, relativePath, keepData);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_main_camera(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->setMainCamera();
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->setMainCamera(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(TViewer *viewer)
|
||||
@@ -217,11 +205,6 @@ extern "C"
|
||||
return ((FilamentViewer *)viewer)->getMainCamera();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool set_camera(TViewer *viewer, EntityId asset, const char *nodeName)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->setCamera(asset, nodeName);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
@@ -246,62 +229,62 @@ extern "C"
|
||||
return reinterpret_cast<TCamera *>(filamentCamera);
|
||||
}
|
||||
|
||||
double4x4 get_camera_model_matrix(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
double4x4 get_camera_view_matrix(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
double4x4 get_camera_projection_matrix(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
double4x4 get_camera_culling_projection_matrix(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const auto &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setCustomProjection(mat, near, far);
|
||||
}
|
||||
|
||||
void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setLensProjection(focalLength, aspect, near, far);
|
||||
}
|
||||
|
||||
void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setModelMatrix(convert_double4x4_to_mat4(matrix));
|
||||
}
|
||||
|
||||
double get_camera_near(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getNear();
|
||||
}
|
||||
|
||||
double get_camera_culling_far(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getCullingFar();
|
||||
}
|
||||
|
||||
const double *const get_camera_frustum(TCamera *camera)
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *camera)
|
||||
{
|
||||
|
||||
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
|
||||
@@ -320,15 +303,6 @@ extern "C"
|
||||
return array;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(TViewer *viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setCameraManipulatorOptions((filament::camutils::Mode)mode, orbitSpeedX, orbitSpeedY, zoomSpeed);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(TViewer *viewer, bool enabled)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setViewFrustumCulling(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
|
||||
{
|
||||
@@ -349,18 +323,24 @@ extern "C"
|
||||
cam->setModelMatrix(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool render(
|
||||
TViewer *viewer,
|
||||
uint64_t frameTimeInNanos,
|
||||
void *pixelBuffer,
|
||||
void (*callback)(void *buf, size_t size, void *data),
|
||||
void *data)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_render(
|
||||
TViewer *tViewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
viewer->render(0);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void capture(
|
||||
TViewer *viewer,
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *tViewer, TSwapChain *tSwapChain, TView *tView, bool renderable) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain*>(tSwapChain);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->setRenderable(view, swapChain, renderable);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
@@ -369,7 +349,30 @@ extern "C"
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
((FilamentViewer *)viewer)->capture(pixelBuffer, useFence, callback);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
TRenderTarget *tRenderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
bool useFence = true;
|
||||
#else
|
||||
bool useFence = false;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, renderTarget, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
||||
@@ -379,56 +382,54 @@ extern "C"
|
||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain *tSwapChain)
|
||||
{
|
||||
((FilamentViewer *)viewer)->destroySwapChain();
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
viewer->destroySwapChain(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain(TViewer *viewer, const void *const window, uint32_t width, uint32_t height)
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *tViewer, uint32_t width, uint32_t height)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createSwapChain(window, width, height);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(width, height);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void update_viewport(TViewer *viewer, uint32_t width, uint32_t height)
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->updateViewport(width, height);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(window);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_update(TViewer *viewer, float x, float y, float delta)
|
||||
{
|
||||
((FilamentViewer *)viewer)->scrollUpdate(x, y, delta);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index) {
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->getSwapChainAt(index);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_begin(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_createView(TViewer *tViewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->scrollBegin();
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->createView();
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void scroll_end(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_getViewAt(TViewer *tViewer, int32_t index)
|
||||
{
|
||||
((FilamentViewer *)viewer)->scrollEnd();
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->getViewAt(index);
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void grab_begin(TViewer *viewer, float x, float y, bool pan)
|
||||
{
|
||||
((FilamentViewer *)viewer)->grabBegin(x, y, pan);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void grab_update(TViewer *viewer, float x, float y)
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *tViewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->grabUpdate(x, y);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void grab_end(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->grabEnd();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager* Viewer_getSceneManager(TViewer *tViewer)
|
||||
{
|
||||
auto * viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
auto * sceneManager = viewer->getSceneManager();
|
||||
return reinterpret_cast<TSceneManager*>(sceneManager);
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *sceneManager = viewer->getSceneManager();
|
||||
return reinterpret_cast<TSceneManager *>(sceneManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void apply_weights(
|
||||
@@ -450,11 +451,11 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->setMorphTargetWeights(asset, weights, numWeights);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool set_morph_animation(
|
||||
EMSCRIPTEN_KEEPALIVE bool SceneManager_setMorphAnimation(
|
||||
TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
const int *const morphIndices,
|
||||
const uint32_t *const morphIndices,
|
||||
int numMorphTargets,
|
||||
int numFrames,
|
||||
float frameLengthInMs)
|
||||
@@ -488,31 +489,6 @@ extern "C"
|
||||
((SceneManager *)sceneManager)->addBoneAnimation(asset, skinIndex, boneIndex, frameData, numFrames, frameLengthInMs, fadeOutInSecs, fadeInInSecs, maxDelta);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setPostProcessing(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadows_enabled(TViewer *viewer, bool enabled)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setShadowsEnabled(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_shadow_type(TViewer *viewer, int shadowType)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setShadowType((ShadowType)shadowType);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_soft_shadow_options(TViewer *viewer, float penumbraScale, float penumbraRatioScale)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setSoftShadowOptions(penumbraScale, penumbraRatioScale);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_antialiasing(TViewer *viewer, bool msaa, bool fxaa, bool taa)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setAntiAliasing(msaa, fxaa, taa);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId get_bone(TSceneManager *sceneManager,
|
||||
EntityId entityId,
|
||||
int skinIndex,
|
||||
@@ -696,6 +672,12 @@ extern "C"
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraByName(TSceneManager *tSceneManager, EntityId entityId, const char* name) {
|
||||
auto *sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool SceneManager_setTransform(TSceneManager *sceneManager, EntityId entityId, const double *const transform)
|
||||
{
|
||||
auto matrix = math::mat4(
|
||||
@@ -716,27 +698,31 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->setTransform(entityId, matrix);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *tSceneManager, EntityId* entities, const double* const transforms, int numEntities) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
math::mat4 matrices[numEntities];
|
||||
for(int i = 0; i < numEntities; i++) {
|
||||
matrices[i] = math::mat4(
|
||||
transforms[i * 16], transforms[i*16+1], transforms[i*16+2],
|
||||
transforms[i*16+3],
|
||||
transforms[i*16+4],
|
||||
transforms[i*16+5],
|
||||
transforms[i*16+6],
|
||||
transforms[i*16+7],
|
||||
transforms[i*16+8],
|
||||
transforms[i*16+9],
|
||||
transforms[i*16+10],
|
||||
transforms[i*16+11],
|
||||
transforms[i*16+12],
|
||||
transforms[i*16+13],
|
||||
transforms[i*16+14],
|
||||
transforms[i*16+15]);
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *tSceneManager, EntityId *entities, const double *const transforms, int numEntities)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
|
||||
std::vector<math::mat4> matrices(
|
||||
numEntities);
|
||||
for (int i = 0; i < numEntities; i++)
|
||||
{
|
||||
matrices[i] = math::mat4(
|
||||
transforms[i * 16], transforms[i * 16 + 1], transforms[i * 16 + 2],
|
||||
transforms[i * 16 + 3],
|
||||
transforms[i * 16 + 4],
|
||||
transforms[i * 16 + 5],
|
||||
transforms[i * 16 + 6],
|
||||
transforms[i * 16 + 7],
|
||||
transforms[i * 16 + 8],
|
||||
transforms[i * 16 + 9],
|
||||
transforms[i * 16 + 10],
|
||||
transforms[i * 16 + 11],
|
||||
transforms[i * 16 + 12],
|
||||
transforms[i * 16 + 13],
|
||||
transforms[i * 16 + 14],
|
||||
transforms[i * 16 + 15]);
|
||||
}
|
||||
sceneManager->queueTransformUpdates(entities, matrices, numEntities);
|
||||
sceneManager->queueTransformUpdates(entities, matrices.data(), numEntities);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(TSceneManager *sceneManager, EntityId entityId)
|
||||
@@ -792,9 +778,10 @@ extern "C"
|
||||
((SceneManager *)sceneManager)->setScale(asset, scale);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, EntityId entity, float viewportX, float viewportY)
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *tView, EntityId entity, float viewportX, float viewportY)
|
||||
{
|
||||
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(entity, viewportX, viewportY);
|
||||
auto *view = reinterpret_cast<View*>(tView);
|
||||
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(view, entity, viewportX, viewportY);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void stop_animation(TSceneManager *sceneManager, EntityId asset, int index)
|
||||
@@ -812,11 +799,6 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->reveal(asset, meshName);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void filament_pick(TViewer *viewer, int x, int y, void (*callback)(EntityId entityId, int x, int y))
|
||||
{
|
||||
((FilamentViewer *)viewer)->pick(static_cast<uint32_t>(x), static_cast<uint32_t>(y), callback);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const char *get_name_for_entity(TSceneManager *sceneManager, const EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getNameForEntity(entityId);
|
||||
@@ -837,16 +819,6 @@ extern "C"
|
||||
return ((SceneManager *)sceneManager)->getEntityNameAt(target, index, renderableOnly);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording(TViewer *viewer, bool recording)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setRecording(recording);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_recording_output_directory(TViewer *viewer, const char *outputDirectory)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setRecordingOutputDirectory(outputDirectory);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy()
|
||||
{
|
||||
Log("Dummy called");
|
||||
@@ -925,37 +897,27 @@ extern "C"
|
||||
((SceneManager *)sceneManager)->setPriority(entity, priority);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_gizmo(TSceneManager *sceneManager, EntityId *out)
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *tView, EntityId entity)
|
||||
{
|
||||
auto gizmo = ((SceneManager *)sceneManager)->gizmo;
|
||||
out[0] = Entity::smuggle(gizmo->x());
|
||||
out[1] = Entity::smuggle(gizmo->y());
|
||||
out[2] = Entity::smuggle(gizmo->z());
|
||||
out[3] = Entity::smuggle(gizmo->center());
|
||||
auto view = reinterpret_cast<View*>(tView);
|
||||
return ((SceneManager *)sceneManager)->getBoundingBox(view, entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, EntityId entity)
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *tView, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getBoundingBox(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
|
||||
{
|
||||
auto box = ((SceneManager *)sceneManager)->getBoundingBox(entity);
|
||||
auto view = reinterpret_cast<View*>(tView);
|
||||
auto box = ((SceneManager *)sceneManager)->getBoundingBox(view, entity);
|
||||
*minX = box.minX;
|
||||
*minY = box.minY;
|
||||
*maxX = box.maxX;
|
||||
*maxY = box.maxY;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_visibility_layer(TSceneManager *sceneManager, EntityId entity, int layer) {
|
||||
((SceneManager*)sceneManager)->setVisibilityLayer(entity, layer);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_layer_visibility(TSceneManager *sceneManager, int layer, bool visible)
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setVisibilityLayer(TSceneManager *tSceneManager, EntityId entity, int layer)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setLayerVisibility((SceneManager::LAYERS)layer, visible);
|
||||
auto *sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
sceneManager->setVisibilityLayer(entity, layer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
|
||||
@@ -963,16 +925,6 @@ extern "C"
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void pick_gizmo(TSceneManager *sceneManager, int x, int y, void (*callback)(EntityId entityId, int x, int y))
|
||||
{
|
||||
((SceneManager *)sceneManager)->gizmo->pick(x, y, callback);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_gizmo_visibility(TSceneManager *sceneManager, bool visible)
|
||||
{
|
||||
((SceneManager *)sceneManager)->gizmo->setVisibility(visible);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_stencil_highlight(TSceneManager *sceneManager, EntityId entityId, float r, float g, float b)
|
||||
{
|
||||
((SceneManager *)sceneManager)->setStencilHighlight(entityId, r, g, b);
|
||||
@@ -988,9 +940,10 @@ extern "C"
|
||||
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, value);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance* get_material_instance_at(TSceneManager *sceneManager, EntityId entity, int materialIndex) {
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *get_material_instance_at(TSceneManager *sceneManager, EntityId entity, int materialIndex)
|
||||
{
|
||||
auto instance = ((SceneManager *)sceneManager)->getMaterialInstanceAt(entity, materialIndex);
|
||||
return reinterpret_cast<TMaterialInstance*>(instance);
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_int(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, int32_t value)
|
||||
@@ -999,16 +952,16 @@ extern "C"
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, double4 value)
|
||||
{
|
||||
{
|
||||
filament::math::float4 filamentValue;
|
||||
filamentValue.x = static_cast<float32_t>(value.x);
|
||||
filamentValue.y = static_cast<float32_t>(value.y);
|
||||
filamentValue.z = static_cast<float32_t>(value.z);
|
||||
filamentValue.w = static_cast<float32_t>(value.w);
|
||||
filamentValue.x = static_cast<float>(value.x);
|
||||
filamentValue.y = static_cast<float>(value.y);
|
||||
filamentValue.z = static_cast<float>(value.z);
|
||||
filamentValue.w = static_cast<float>(value.w);
|
||||
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, filamentValue);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||
EMSCRIPTEN_KEEPALIVE void unproject_texture(TViewer *viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->unprojectTexture(entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
|
||||
}
|
||||
@@ -1028,146 +981,113 @@ extern "C"
|
||||
((SceneManager *)sceneManager)->destroyTexture(reinterpret_cast<Texture *>(texture));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_material_instance(TSceneManager *sceneManager, TMaterialKey materialConfig)
|
||||
{
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance* create_material_instance(TSceneManager *sceneManager, TMaterialKey materialConfig)
|
||||
{
|
||||
filament::gltfio::MaterialKey config;
|
||||
memset(&config, 0, sizeof(MaterialKey));
|
||||
|
||||
filament::gltfio::MaterialKey config;
|
||||
memset(&config, 0, sizeof(MaterialKey));
|
||||
|
||||
// Set and log each field
|
||||
config.unlit = materialConfig.unlit;
|
||||
config.doubleSided = materialConfig.doubleSided;
|
||||
config.useSpecularGlossiness = materialConfig.useSpecularGlossiness;
|
||||
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig.alphaMode);
|
||||
config.hasBaseColorTexture = materialConfig.hasBaseColorTexture;
|
||||
config.hasClearCoat = materialConfig.hasClearCoat;
|
||||
config.hasClearCoatNormalTexture = materialConfig.hasClearCoatNormalTexture;
|
||||
config.hasClearCoatRoughnessTexture = materialConfig.hasClearCoatRoughnessTexture;
|
||||
config.hasEmissiveTexture = materialConfig.hasEmissiveTexture;
|
||||
config.hasIOR = materialConfig.hasIOR;
|
||||
config.hasMetallicRoughnessTexture = materialConfig.hasMetallicRoughnessTexture;
|
||||
config.hasNormalTexture = materialConfig.hasNormalTexture;
|
||||
config.hasOcclusionTexture = materialConfig.hasOcclusionTexture;
|
||||
config.hasSheen = materialConfig.hasSheen;
|
||||
config.hasSheenColorTexture = materialConfig.hasSheenColorTexture;
|
||||
config.hasSheenRoughnessTexture = materialConfig.hasSheenRoughnessTexture;
|
||||
config.hasTextureTransforms = materialConfig.hasTextureTransforms;
|
||||
config.hasTransmission = materialConfig.hasTransmission;
|
||||
config.hasTransmissionTexture = materialConfig.hasTransmissionTexture;
|
||||
config.hasVolume = materialConfig.hasVolume;
|
||||
config.hasVolumeThicknessTexture = materialConfig.hasVolumeThicknessTexture;
|
||||
config.baseColorUV = materialConfig.baseColorUV;
|
||||
config.hasVertexColors = materialConfig.hasVertexColors;
|
||||
auto materialInstance = ((SceneManager *)sceneManager)->createUbershaderMaterialInstance(config);
|
||||
return reinterpret_cast<TMaterialInstance*>(materialInstance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_unlit_material_instance(TSceneManager *sceneManager) {
|
||||
auto * instance = ((SceneManager*)sceneManager)->createUnlitMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance*>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_material_instance(TSceneManager *sceneManager, TMaterialInstance *instance) {
|
||||
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance*>(instance));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* materialInstance, bool enabled) {
|
||||
reinterpret_cast<MaterialInstance*>(materialInstance)->setDepthWrite(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled) {
|
||||
reinterpret_cast<MaterialInstance*>(materialInstance)->setDepthCulling(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance* materialInstance, const char* propertyName, double x, double y) {
|
||||
filament::math::float2 data { static_cast<float>(x), static_cast<float>(y) };
|
||||
reinterpret_cast<MaterialInstance*>(materialInstance)->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* tCamera, double4x4 projectionMatrix, double near, double far) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
camera->setCustomProjection(convert_double4x4_to_mat4(projectionMatrix), near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getModelMatrix(TCamera* tCamera) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
return convert_mat4_to_double4x4(camera->getModelMatrix());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 Camera_getViewMatrix(TCamera *const tCamera) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
return convert_mat4_to_double4x4(camera->getViewMatrix());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera* tCamera) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
return Entity::smuggle(camera->getEntity());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const tCamera) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
return camera->getFocalLength();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *const tCamera) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
return camera->getNear();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *const tCamera) {
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
return camera->getCullingFar();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId) {
|
||||
auto * engine = reinterpret_cast<Engine*>(tEngine);
|
||||
auto * camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
||||
return reinterpret_cast<TCamera*>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine* tEngine, EntityId entity, double4x4 transform) {
|
||||
auto * engine = reinterpret_cast<Engine*>(tEngine);
|
||||
auto& transformManager = engine->getTransformManager();
|
||||
|
||||
auto transformInstance = transformManager.getInstance(utils::Entity::import(entity));
|
||||
if(!transformInstance.isValid()) {
|
||||
Log("Transform instance not valid");
|
||||
// Set and log each field
|
||||
config.unlit = materialConfig.unlit;
|
||||
config.doubleSided = materialConfig.doubleSided;
|
||||
config.useSpecularGlossiness = materialConfig.useSpecularGlossiness;
|
||||
config.alphaMode = static_cast<filament::gltfio::AlphaMode>(materialConfig.alphaMode);
|
||||
config.hasBaseColorTexture = materialConfig.hasBaseColorTexture;
|
||||
config.hasClearCoat = materialConfig.hasClearCoat;
|
||||
config.hasClearCoatNormalTexture = materialConfig.hasClearCoatNormalTexture;
|
||||
config.hasClearCoatRoughnessTexture = materialConfig.hasClearCoatRoughnessTexture;
|
||||
config.hasEmissiveTexture = materialConfig.hasEmissiveTexture;
|
||||
config.hasIOR = materialConfig.hasIOR;
|
||||
config.hasMetallicRoughnessTexture = materialConfig.hasMetallicRoughnessTexture;
|
||||
config.hasNormalTexture = materialConfig.hasNormalTexture;
|
||||
config.hasOcclusionTexture = materialConfig.hasOcclusionTexture;
|
||||
config.hasSheen = materialConfig.hasSheen;
|
||||
config.hasSheenColorTexture = materialConfig.hasSheenColorTexture;
|
||||
config.hasSheenRoughnessTexture = materialConfig.hasSheenRoughnessTexture;
|
||||
config.hasTextureTransforms = materialConfig.hasTextureTransforms;
|
||||
config.hasTransmission = materialConfig.hasTransmission;
|
||||
config.hasTransmissionTexture = materialConfig.hasTransmissionTexture;
|
||||
config.hasVolume = materialConfig.hasVolume;
|
||||
config.hasVolumeThicknessTexture = materialConfig.hasVolumeThicknessTexture;
|
||||
config.baseColorUV = materialConfig.baseColorUV;
|
||||
config.hasVertexColors = materialConfig.hasVertexColors;
|
||||
auto materialInstance = ((SceneManager *)sceneManager)->createUbershaderMaterialInstance(config);
|
||||
return reinterpret_cast<TMaterialInstance *>(materialInstance);
|
||||
}
|
||||
transformManager.setTransform(transformInstance, convert_double4x4_to_mat4(transform));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager* tSceneManager) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
return reinterpret_cast<TCamera*>(sceneManager->createCamera());
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *create_unlit_material_instance(TSceneManager *sceneManager)
|
||||
{
|
||||
auto *instance = ((SceneManager *)sceneManager)->createUnlitMaterialInstance();
|
||||
return reinterpret_cast<TMaterialInstance *>(instance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager* tSceneManager, TCamera* tCamera) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
sceneManager->destroyCamera(camera);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_material_instance(TSceneManager *sceneManager, TMaterialInstance *instance)
|
||||
{
|
||||
((SceneManager *)sceneManager)->destroy(reinterpret_cast<MaterialInstance *>(instance));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setCamera(TSceneManager* tSceneManager, TCamera* tCamera) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||
sceneManager->setCamera(camera);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<MaterialInstance *>(materialInstance)->setDepthWrite(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *tSceneManager) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
return sceneManager->getCameraCount();
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraAt(TSceneManager *tSceneManager, size_t index) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
auto * camera = sceneManager->getCameraAt(index);
|
||||
return reinterpret_cast<TCamera*>(camera);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance *materialInstance, bool enabled)
|
||||
{
|
||||
reinterpret_cast<MaterialInstance *>(materialInstance)->setDepthCulling(enabled);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setParameterFloat2(TMaterialInstance *materialInstance, const char *propertyName, double x, double y)
|
||||
{
|
||||
filament::math::float2 data{static_cast<float>(x), static_cast<float>(y)};
|
||||
reinterpret_cast<MaterialInstance *>(materialInstance)->setParameter(propertyName, data);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine *tEngine, EntityId entityId)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto *camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
||||
return reinterpret_cast<TCamera *>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_setTransform(TEngine *tEngine, EntityId entity, double4x4 transform)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto &transformManager = engine->getTransformManager();
|
||||
|
||||
auto transformInstance = transformManager.getInstance(utils::Entity::import(entity));
|
||||
if (!transformInstance.isValid())
|
||||
{
|
||||
Log("Transform instance not valid");
|
||||
}
|
||||
transformManager.setTransform(transformInstance, convert_double4x4_to_mat4(transform));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_createCamera(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return reinterpret_cast<TCamera *>(sceneManager->createCamera());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_destroyCamera(TSceneManager *tSceneManager, TCamera *tCamera)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *camera = reinterpret_cast<Camera *>(tCamera);
|
||||
sceneManager->destroyCamera(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *tSceneManager)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
return sceneManager->getCameraCount();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *SceneManager_getCameraAt(TSceneManager *tSceneManager, size_t index)
|
||||
{
|
||||
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
|
||||
auto *camera = sceneManager->getCameraAt(index);
|
||||
return reinterpret_cast<TCamera *>(camera);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getActiveCamera(TSceneManager *tSceneManager) {
|
||||
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||
auto * camera = sceneManager->getActiveCamera();
|
||||
return reinterpret_cast<TCamera*>(camera);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,6 @@
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#define GL_GLEXT_PROTOTYPES
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glext.h>
|
||||
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/threading.h>
|
||||
#include <emscripten/val.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "ThermionDartRenderThreadApi.h"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "TView.h"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
#include "filament/LightManager.h"
|
||||
@@ -26,7 +10,7 @@ extern "C"
|
||||
#include <thread>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace thermion_filament;
|
||||
using namespace thermion;
|
||||
using namespace std::chrono_literals;
|
||||
#include <time.h>
|
||||
|
||||
@@ -36,27 +20,16 @@ public:
|
||||
explicit RenderLoop()
|
||||
{
|
||||
srand(time(NULL));
|
||||
#ifdef __EMSCRIPTEN__
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
|
||||
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
|
||||
#else
|
||||
t = new std::thread([this]()
|
||||
{ start(); });
|
||||
#endif
|
||||
}
|
||||
|
||||
~RenderLoop()
|
||||
{
|
||||
_render = false;
|
||||
_stop = true;
|
||||
swapChain = nullptr;
|
||||
_cv.notify_one();
|
||||
#ifdef __EMSCRIPTEN__
|
||||
pthread_join(t, NULL);
|
||||
#else
|
||||
t->join();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void mainLoop(void *arg)
|
||||
@@ -66,11 +39,7 @@ public:
|
||||
|
||||
static void *startHelper(void *parm)
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
emscripten_set_main_loop_arg(&RenderLoop::mainLoop, parm, 0, true);
|
||||
#else
|
||||
((RenderLoop *)parm)->start();
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -84,49 +53,53 @@ public:
|
||||
|
||||
void requestFrame(void (*callback)())
|
||||
{
|
||||
this->_render = true;
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
this->_requestFrameRenderCallback = callback;
|
||||
_cv.notify_one();
|
||||
}
|
||||
|
||||
void iter()
|
||||
void iter()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (_render)
|
||||
{
|
||||
doRender();
|
||||
this->_requestFrameRenderCallback();
|
||||
_render = false;
|
||||
|
||||
// Calculate and print FPS
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - _lastFrameTime).count();
|
||||
_lastFrameTime = currentTime;
|
||||
|
||||
_frameCount++;
|
||||
_accumulatedTime += deltaTime;
|
||||
|
||||
if (_accumulatedTime >= 1.0f) // Update FPS every second
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (_requestFrameRenderCallback)
|
||||
{
|
||||
_fps = _frameCount / _accumulatedTime;
|
||||
std::cout << "FPS: " << _fps << std::endl;
|
||||
_frameCount = 0;
|
||||
_accumulatedTime = 0.0f;
|
||||
doRender();
|
||||
lock.unlock();
|
||||
this->_requestFrameRenderCallback();
|
||||
this->_requestFrameRenderCallback = nullptr;
|
||||
|
||||
// Calculate and print FPS
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - _lastFrameTime).count();
|
||||
_lastFrameTime = currentTime;
|
||||
|
||||
_frameCount++;
|
||||
_accumulatedTime += deltaTime;
|
||||
|
||||
if (_accumulatedTime >= 1.0f) // Update FPS every second
|
||||
{
|
||||
_fps = _frameCount / _accumulatedTime;
|
||||
// std::cout << "FPS: " << _fps << std::endl;
|
||||
_frameCount = 0;
|
||||
_accumulatedTime = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> taskLock(_taskMutex);
|
||||
|
||||
if (!_tasks.empty())
|
||||
{
|
||||
auto task = std::move(_tasks.front());
|
||||
_tasks.pop_front();
|
||||
lock.unlock();
|
||||
taskLock.unlock();
|
||||
task();
|
||||
lock.lock();
|
||||
taskLock.lock();
|
||||
}
|
||||
|
||||
_cv.wait_for(lock, std::chrono::microseconds(1000), [this]
|
||||
{ return !_tasks.empty() || _stop || _render; });
|
||||
_cv.wait_for(taskLock, std::chrono::microseconds(2000), [this]
|
||||
{ return !_tasks.empty() || _stop; });
|
||||
|
||||
if (_stop)
|
||||
return;
|
||||
}
|
||||
|
||||
void createViewer(void *const context,
|
||||
@@ -141,26 +114,9 @@ public:
|
||||
_renderCallbackOwner = owner;
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
_context = thermion_dart_web_create_gl_context();
|
||||
|
||||
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
|
||||
if (success != EMSCRIPTEN_RESULT_SUCCESS)
|
||||
{
|
||||
std::cout << "Failed to make context current." << std::endl;
|
||||
return;
|
||||
}
|
||||
glClearColor(0.0, 0.5, 0.5, 1.0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
// emscripten_webgl_commit_frame();
|
||||
|
||||
_viewer = (FilamentViewer *)create_filament_viewer((void *const)_context, loader, platform, uberArchivePath);
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, _viewer);
|
||||
#else
|
||||
auto viewer = (FilamentViewer *)create_filament_viewer(context, loader, platform, uberArchivePath);
|
||||
auto viewer = (FilamentViewer *)Viewer_create(context, loader, platform, uberArchivePath);
|
||||
_viewer = reinterpret_cast<TViewer*>(viewer);
|
||||
callback(_viewer);
|
||||
#endif
|
||||
});
|
||||
auto fut = add_task(lambda);
|
||||
}
|
||||
@@ -169,45 +125,31 @@ public:
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
_render = false;
|
||||
swapChain = nullptr;
|
||||
_viewer = nullptr;
|
||||
destroy_filament_viewer(reinterpret_cast<TViewer*>(viewer)); });
|
||||
auto fut = add_task(lambda);
|
||||
fut.wait();
|
||||
}
|
||||
|
||||
bool doRender()
|
||||
void doRender()
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
if (emscripten_is_webgl_context_lost(_context) == EM_TRUE)
|
||||
{
|
||||
Log("Context lost");
|
||||
auto sleepFor = std::chrono::seconds(1);
|
||||
std::this_thread::sleep_for(sleepFor);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
auto rendered = render(_viewer, 0, nullptr, nullptr, nullptr);
|
||||
Viewer_render(_viewer);
|
||||
if (_renderCallback)
|
||||
{
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
}
|
||||
return rendered;
|
||||
#ifdef __EMSCRIPTEN__
|
||||
// emscripten_webgl_commit_frame();
|
||||
#endif
|
||||
}
|
||||
|
||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
_frameIntervalInMicroseconds = static_cast<int>(1000.0f * frameIntervalInMilliseconds);
|
||||
}
|
||||
|
||||
template <class Rt>
|
||||
auto add_task(std::packaged_task<Rt()> &pt) -> std::future<Rt>
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
std::unique_lock<std::mutex> lock(_taskMutex);
|
||||
auto ret = pt.get_future();
|
||||
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
|
||||
std::move(pt))]
|
||||
@@ -217,13 +159,14 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
std::atomic_bool _render = false;
|
||||
TSwapChain *swapChain;
|
||||
|
||||
private:
|
||||
void(*_requestFrameRenderCallback)() = nullptr;
|
||||
bool _stop = false;
|
||||
int _frameIntervalInMicroseconds = 1000000 / 60;
|
||||
std::mutex _mutex;
|
||||
std::mutex _taskMutex;
|
||||
std::condition_variable _cv;
|
||||
void (*_renderCallback)(void *const) = nullptr;
|
||||
void *_renderCallbackOwner = nullptr;
|
||||
@@ -233,13 +176,7 @@ private:
|
||||
int _frameCount = 0;
|
||||
float _accumulatedTime = 0.0f;
|
||||
float _fps = 0.0f;
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
pthread_t t;
|
||||
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
|
||||
#else
|
||||
std::thread *t = nullptr;
|
||||
#endif
|
||||
};
|
||||
|
||||
extern "C"
|
||||
@@ -247,7 +184,7 @@ extern "C"
|
||||
|
||||
static RenderLoop *_rl;
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_render_thread(
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
|
||||
void *const context, void *const platform, const char *uberArchivePath,
|
||||
const void *const loader,
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
@@ -270,59 +207,46 @@ extern "C"
|
||||
_rl = nullptr;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(TViewer *viewer,
|
||||
void *const surface,
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)())
|
||||
void (*onComplete)(TSwapChain*))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
create_swap_chain(viewer, surface, width, height);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete();
|
||||
#endif
|
||||
auto *swapChain = Viewer_createHeadlessSwapChain(viewer, width, height);
|
||||
onComplete(swapChain);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(TViewer *viewer, void (*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer,
|
||||
void *const surface,
|
||||
void (*onComplete)(TSwapChain*))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
destroy_swap_chain(viewer);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete();
|
||||
#endif
|
||||
auto *swapChain = Viewer_createSwapChain(viewer, surface);
|
||||
onComplete(swapChain);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(TViewer *viewer,
|
||||
intptr_t nativeTextureId,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
create_render_target(viewer, nativeTextureId, width, height);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete();
|
||||
#endif
|
||||
});
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_destroySwapChain(viewer, swapChain);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(TViewer *viewer, void(*onComplete)())
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)())
|
||||
{
|
||||
if (!_rl)
|
||||
{
|
||||
@@ -334,6 +258,16 @@ extern "C"
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void(*onComplete)()) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_loadIbl(viewer, iblPath, intensity);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
set_frame_interval_render_thread(TViewer *viewer, float frameIntervalInMilliseconds)
|
||||
{
|
||||
@@ -343,17 +277,26 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void render_render_thread(TViewer *viewer)
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *tView, TSwapChain *tSwapChain)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ _rl->doRender(); });
|
||||
{
|
||||
_rl->doRender();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void capture_render_thread(TViewer *viewer, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ capture(viewer, pixelBuffer, onComplete); });
|
||||
{ Viewer_capture(viewer, view, tSwapChain, pixelBuffer, onComplete); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget* tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ Viewer_captureRenderTarget(viewer, view, tSwapChain, tRenderTarget, pixelBuffer, onComplete); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
@@ -376,13 +319,7 @@ extern "C"
|
||||
std::packaged_task<EntityId()> lambda([=]() mutable
|
||||
{
|
||||
auto entity = load_gltf(sceneManager, path, relativeResourcePath, keepData);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({
|
||||
moduleArg.dartFilamentResolveCallback($0, $1);
|
||||
}, callback, entity);
|
||||
#else
|
||||
callback(entity);
|
||||
#endif
|
||||
callback(entity);
|
||||
return entity; });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -397,29 +334,26 @@ extern "C"
|
||||
[=]() mutable
|
||||
{
|
||||
auto entity = load_glb(sceneManager, path, numInstances, keepData);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, entity);
|
||||
#else
|
||||
callback(entity);
|
||||
#endif
|
||||
return entity;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(TSceneManager *sceneManager,
|
||||
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))
|
||||
{
|
||||
std::packaged_task<EntityId()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto entity = load_glb_from_buffer(sceneManager, data, length, keepData, priority, layer);
|
||||
auto entity = SceneManager_loadGlbFromBuffer(sceneManager, data, length, keepData, priority, layer, loadResourcesAsync);
|
||||
callback(entity);
|
||||
return entity;
|
||||
});
|
||||
@@ -441,14 +375,11 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
set_background_image(viewer, path, fillHeight);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer,
|
||||
float x, float y,
|
||||
bool clamp)
|
||||
@@ -458,20 +389,7 @@ extern "C"
|
||||
{ set_background_image_position(viewer, x, y, clamp); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(TViewer *viewer,
|
||||
int toneMapping)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ set_tone_mapping(viewer, toneMapping); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(TViewer *viewer, float strength)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{ set_bloom(viewer, strength); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer,
|
||||
const char *skyboxPath,
|
||||
void (*onComplete)())
|
||||
@@ -479,23 +397,11 @@ extern "C"
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
load_skybox(viewer, skyboxPath);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
|
||||
#else
|
||||
onComplete();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void load_ibl_render_thread(TViewer *viewer, const char *iblPath,
|
||||
float intensity)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ load_ibl(viewer, iblPath, intensity); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]
|
||||
@@ -516,11 +422,7 @@ extern "C"
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
remove_entity(viewer, asset);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -530,31 +432,11 @@ extern "C"
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
clear_entities(viewer);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(TViewer *viewer, EntityId asset,
|
||||
const char *nodeName, void (*callback)(bool))
|
||||
{
|
||||
std::packaged_task<bool()> lambda(
|
||||
[=]
|
||||
{
|
||||
auto success = set_camera(viewer, asset, nodeName);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, success);
|
||||
#else
|
||||
callback(success);
|
||||
#endif
|
||||
return success;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
|
||||
@@ -563,11 +445,7 @@ extern "C"
|
||||
std::packaged_task<void()> lambda([=]
|
||||
{
|
||||
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -579,13 +457,7 @@ extern "C"
|
||||
std::packaged_task<int()> lambda([=]
|
||||
{
|
||||
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({
|
||||
moduleArg.dartFilamentResolveCallback($0,$1);
|
||||
}, callback, count);
|
||||
#else
|
||||
callback(count);
|
||||
#endif
|
||||
return count; });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -617,11 +489,7 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
auto count = get_animation_count(sceneManager, asset);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, count);
|
||||
#else
|
||||
callback(count);
|
||||
#endif
|
||||
return count;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
@@ -637,24 +505,11 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
get_animation_name(sceneManager, asset, outPtr, index);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer,
|
||||
bool enabled)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{ set_post_processing(viewer, enabled); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
get_name_for_entity_render_thread(TSceneManager *sceneManager, const EntityId entityId, void (*callback)(const char *))
|
||||
{
|
||||
@@ -662,17 +517,13 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
auto name = get_name_for_entity(sceneManager, entityId);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, name);
|
||||
#else
|
||||
callback(name);
|
||||
#endif
|
||||
return name;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
void set_morph_target_weights_render_thread(TSceneManager *sceneManager,
|
||||
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(TSceneManager *sceneManager,
|
||||
EntityId asset,
|
||||
const float *const morphData,
|
||||
int numWeights,
|
||||
@@ -682,11 +533,7 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, result);
|
||||
#else
|
||||
callback(result);
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -703,11 +550,7 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, success);
|
||||
#else
|
||||
callback(success);
|
||||
#endif
|
||||
return success;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
@@ -720,11 +563,25 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
auto success = update_bone_matrices(sceneManager, entity);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback, success);
|
||||
#else
|
||||
callback(success);
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
View_setToneMapping(tView, tEngine, toneMapping);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]
|
||||
{
|
||||
View_setBloom(tView, bloom);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -735,11 +592,7 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
reset_to_rest_pose(sceneManager, entityId);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
|
||||
#else
|
||||
callback();
|
||||
#endif
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
@@ -763,11 +616,7 @@ extern "C"
|
||||
[=]
|
||||
{
|
||||
auto entity = create_geometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstance, keepData);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, entity);
|
||||
#else
|
||||
callback(entity);
|
||||
#endif
|
||||
return entity;
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
|
||||
36
thermion_dart/native/src/ThermionWin32.h
Normal file
36
thermion_dart/native/src/ThermionWin32.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#pragma comment(lib, "Shlwapi.lib")
|
||||
#pragma comment(lib, "opengl32.lib")
|
||||
#pragma comment(lib, "gdi32.lib")
|
||||
#pragma comment(lib, "user32.lib")
|
||||
#pragma comment(lib, "shell32.lib")
|
||||
#pragma comment(lib, "dwmapi.lib")
|
||||
#pragma comment(lib, "comctl32.lib")
|
||||
#pragma comment(lib, "filament.lib")
|
||||
#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")
|
||||
#pragma comment(lib, "filabridge.lib")
|
||||
#pragma comment(lib, "gltfio_core.lib")
|
||||
#pragma comment(lib, "filament-iblprefilter.lib")
|
||||
#pragma comment(lib, "image.lib")
|
||||
#pragma comment(lib, "imageio.lib")
|
||||
#pragma comment(lib, "tinyexr.lib")
|
||||
#pragma comment(lib, "filaflat.lib")
|
||||
#pragma comment(lib, "dracodec.lib")
|
||||
#pragma comment(lib, "ibl.lib")
|
||||
#pragma comment(lib, "ktxreader.lib")
|
||||
#pragma comment(lib, "png.lib")
|
||||
#pragma comment(lib, "z.lib")
|
||||
#pragma comment(lib, "stb.lib")
|
||||
#pragma comment(lib, "uberzlib.lib")
|
||||
#pragma comment(lib, "smol-v.lib")
|
||||
#pragma comment(lib, "uberarchive.lib")
|
||||
#pragma comment(lib, "zstd.lib")
|
||||
#pragma comment(lib, "basis_transcoder.lib")
|
||||
@@ -20,7 +20,7 @@
|
||||
#include "CustomGeometry.hpp"
|
||||
#include "UnprojectTexture.hpp"
|
||||
|
||||
namespace thermion_filament
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
bool UnprojectTexture::isInsideTriangle(const math::float2 &p, const math::float2 &a, const math::float2 &b, const math::float2 &c)
|
||||
@@ -207,5 +207,5 @@ namespace thermion_filament
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace thermion_filament
|
||||
} // namespace thermion
|
||||
|
||||
|
||||
@@ -177,6 +177,8 @@ namespace filament
|
||||
case Mode::ORBIT:
|
||||
return new OrbitManipulator<FLOAT>(mode, details);
|
||||
}
|
||||
// just to make MSVC happy
|
||||
return new OrbitManipulator<FLOAT>(mode, details);
|
||||
}
|
||||
|
||||
template <typename FLOAT>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: thermion_dart
|
||||
description: 3D rendering toolkit for Dart.
|
||||
version: 0.2.0-dev.7.0
|
||||
version: 0.2.1-dev.0.0.6
|
||||
homepage: https://thermion.dev
|
||||
repository: https://github.com/nmfisher/thermion
|
||||
|
||||
@@ -11,17 +11,20 @@ dependencies:
|
||||
vector_math: ^2.1.2
|
||||
plugin_platform_interface: ^2.0.0
|
||||
ffi: ^2.1.2
|
||||
animation_tools_dart: ^0.0.4
|
||||
animation_tools_dart: ^0.1.0
|
||||
native_toolchain_c: ^0.4.2
|
||||
native_assets_cli: ^0.6.1
|
||||
archive: ^3.6.1
|
||||
web: ^1.0.0
|
||||
logging: ^1.2.0
|
||||
http: ^1.2.2
|
||||
|
||||
|
||||
dev_dependencies:
|
||||
ffigen: ^12.0.0
|
||||
ffigen: ^13.0.0
|
||||
objective_c: ^1.1.0
|
||||
test:
|
||||
image:
|
||||
path:
|
||||
mockito: ^5.0.0
|
||||
build_runner: ^2.0.0
|
||||
build_runner: ^2.0.0
|
||||
|
||||
36
thermion_dart/test/animation_tests.dart
Normal file
36
thermion_dart/test/animation_tests.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
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';
|
||||
|
||||
void main() async {
|
||||
final testHelper = TestHelper("animation");
|
||||
|
||||
group('morph animation tests', () {
|
||||
test('set morph animation', () async {
|
||||
var viewer = await testHelper.createViewer(
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 5));
|
||||
|
||||
final cube = await viewer
|
||||
.loadGlb("${testHelper.testDir}/assets/cube_with_morph_targets.glb");
|
||||
var morphData = MorphAnimationData(
|
||||
Float32List.fromList(List<double>.generate(60, (i) => i / 60)),
|
||||
["Key 1"]);
|
||||
|
||||
await viewer.setMorphAnimationData(cube, morphData);
|
||||
for (int i = 0; i < 60; i++) {
|
||||
await viewer.requestFrame();
|
||||
await Future.delayed(Duration(milliseconds: 17));
|
||||
}
|
||||
|
||||
await testHelper.capture(viewer, "morph_animation");
|
||||
await viewer.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
Binary file not shown.
BIN
thermion_dart/test/assets/cube_with_morph_targets.glb
Normal file
BIN
thermion_dart/test/assets/cube_with_morph_targets.glb
Normal file
Binary file not shown.
@@ -8,7 +8,7 @@ void main() async {
|
||||
|
||||
group('camera', () {
|
||||
test('getCameraModelMatrix, getCameraPosition, rotation', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
var matrix = await viewer.getCameraModelMatrix();
|
||||
expect(matrix.trace(), 4);
|
||||
|
||||
@@ -26,7 +26,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('getCameraViewMatrix', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var modelMatrix = await viewer.getCameraModelMatrix();
|
||||
var viewMatrix = await viewer.getCameraViewMatrix();
|
||||
@@ -49,34 +49,47 @@ void main() async {
|
||||
});
|
||||
|
||||
test('getCameraProjectionMatrix', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
var projectionMatrix = await viewer.getCameraProjectionMatrix();
|
||||
print(projectionMatrix);
|
||||
});
|
||||
|
||||
test('getCameraCullingProjectionMatrix', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
var matrix = await viewer.getCameraCullingProjectionMatrix();
|
||||
print(matrix);
|
||||
throw Exception("TODO");
|
||||
});
|
||||
|
||||
test('getCameraFrustum', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
var frustum = await viewer.getCameraFrustum();
|
||||
print(frustum.plane5.normal);
|
||||
print(frustum.plane5.constant);
|
||||
|
||||
await viewer.setCameraLensProjection(
|
||||
var camera = await viewer.getMainCamera();
|
||||
|
||||
await camera.setLensProjection(
|
||||
near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0);
|
||||
frustum = await viewer.getCameraFrustum();
|
||||
print(frustum.plane5.normal);
|
||||
print(frustum.plane5.constant);
|
||||
});
|
||||
|
||||
test('set orthographic projection', () async {
|
||||
var viewer = await testHelper.createViewer(
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 4));
|
||||
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");
|
||||
});
|
||||
|
||||
test('set custom projection/culling matrix', () async {
|
||||
var viewer =
|
||||
await createViewer(bg: kRed, cameraPosition: Vector3(0, 0, 4));
|
||||
var viewer = await testHelper.createViewer(
|
||||
bg: kRed, cameraPosition: Vector3(0, 0, 4));
|
||||
var camera = await viewer.getMainCamera();
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
@@ -98,7 +111,7 @@ void main() async {
|
||||
|
||||
test('setting transform on camera updates model matrix (no parent)',
|
||||
() async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var cameraEntity = await viewer.getMainCameraEntity();
|
||||
var camera = await viewer.getMainCamera();
|
||||
@@ -114,7 +127,7 @@ void main() async {
|
||||
|
||||
test('setting transform on camera updates model matrix (with parent)',
|
||||
() async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var cameraEntity = await viewer.getMainCameraEntity();
|
||||
var camera = await viewer.getMainCamera();
|
||||
@@ -140,7 +153,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('create camera', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 5);
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
||||
@@ -155,7 +168,7 @@ void main() async {
|
||||
expect(await viewer.getActiveCamera(), newCamera);
|
||||
|
||||
await testHelper.capture(viewer, "create_camera_new_camera");
|
||||
|
||||
|
||||
final mainCamera = await viewer.getMainCamera();
|
||||
await viewer.setActiveCamera(mainCamera);
|
||||
expect(await viewer.getActiveCamera(), mainCamera);
|
||||
|
||||
181
thermion_dart/test/geometry_tests.dart
Normal file
181
thermion_dart/test/geometry_tests.dart
Normal file
@@ -0,0 +1,181 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
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("geometry");
|
||||
group("custom geometry", () {
|
||||
test('create cube (no uvs/normals)', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
|
||||
|
||||
await testHelper.capture(viewer, "geometry_cube_no_uv_no_normal");
|
||||
});
|
||||
|
||||
test('create cube (no normals)', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
var light = await viewer.addLight(
|
||||
LightType.POINT, 6500, 10000000, 0, 2, 0, 0, 0, 0,
|
||||
falloffRadius: 100.0);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
|
||||
await testHelper.capture(viewer, "geometry_cube_no_normals");
|
||||
});
|
||||
|
||||
test('create cube (with normals)', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var light = await viewer.addLight(
|
||||
LightType.POINT, 6500, 10000000, 0, 2, 0, 0, 0, 0,
|
||||
falloffRadius: 100.0);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.cube(normals: true, uvs: false));
|
||||
await testHelper.capture(viewer, "geometry_cube_with_normals");
|
||||
});
|
||||
|
||||
test('create cube with custom ubershader material instance (color)',
|
||||
() async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
var materialInstance =
|
||||
await viewer.createUbershaderMaterialInstance(unlit: true);
|
||||
final cube = await viewer.createGeometry(
|
||||
GeometryHelper.cube(uvs: false, normals: true),
|
||||
materialInstance: materialInstance);
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 0.0);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_ubershader");
|
||||
await viewer.removeEntity(cube);
|
||||
await viewer.destroyMaterialInstance(materialInstance);
|
||||
});
|
||||
|
||||
test('create cube with custom ubershader material instance (texture)',
|
||||
() async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
|
||||
var materialInstance = await viewer.createUbershaderMaterialInstance();
|
||||
final cube = await viewer.createGeometry(
|
||||
GeometryHelper.cube(uvs: true, normals: true),
|
||||
materialInstance: materialInstance);
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
|
||||
.readAsBytesSync();
|
||||
var texture = await viewer.createTexture(textureData);
|
||||
await viewer.applyTexture(texture as ThermionFFITexture, cube);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_ubershader_texture");
|
||||
await viewer.removeEntity(cube);
|
||||
await viewer.destroyMaterialInstance(materialInstance);
|
||||
await viewer.destroyTexture(texture);
|
||||
});
|
||||
|
||||
test('unlit material with color only', () 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.createUnlitMaterialInstance();
|
||||
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_material_base_color");
|
||||
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('create cube with custom material instance (unlit)', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
|
||||
var materialInstance = await viewer.createUnlitMaterialInstance();
|
||||
var cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png")
|
||||
.readAsBytesSync();
|
||||
var texture = await viewer.createTexture(textureData);
|
||||
await viewer.applyTexture(texture, cube);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_unlit_texture_only");
|
||||
await viewer.removeEntity(cube);
|
||||
|
||||
cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
// reusing same material instance, so set baseColorIndex to -1 to disable the texture
|
||||
await viewer.setMaterialPropertyInt(cube, "baseColorIndex", 0, -1);
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_unlit_color_only");
|
||||
await viewer.removeEntity(cube);
|
||||
|
||||
cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
// now set baseColorIndex to 0 to enable the texture and the base color
|
||||
await viewer.setMaterialPropertyInt(cube, "baseColorIndex", 0, 0);
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 0.5);
|
||||
await viewer.applyTexture(texture, cube);
|
||||
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_unlit_color_and_texture");
|
||||
|
||||
await viewer.removeEntity(cube);
|
||||
|
||||
await viewer.destroyTexture(texture);
|
||||
await viewer.destroyMaterialInstance(materialInstance);
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('create sphere (no normals)', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.sphere(normals: false, uvs: false));
|
||||
await testHelper.capture(viewer, "geometry_sphere_no_normals");
|
||||
});
|
||||
});
|
||||
}
|
||||
17
thermion_dart/test/gizmo_tests.dart
Normal file
17
thermion_dart/test/gizmo_tests.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
void main() async {
|
||||
final testHelper = TestHelper("gizmo");
|
||||
|
||||
group('gizmo', () {
|
||||
test('add gizmo to scene', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
var view = await viewer.getViewAt(0);
|
||||
var gizmo = await viewer.createGizmo(view);
|
||||
await testHelper.capture(viewer, "gizmo_add_to_scene");
|
||||
await viewer.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
56
thermion_dart/test/gltf_tests.dart
Normal file
56
thermion_dart/test/gltf_tests.dart
Normal file
@@ -0,0 +1,56 @@
|
||||
import 'dart:io';
|
||||
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("gltf");
|
||||
group("gltf", () {
|
||||
test('load glb from file', () async {
|
||||
var viewer = await testHelper.createViewer(bg: kRed, cameraPosition: Vector3(0, 1, 5));
|
||||
var model = await viewer.loadGlb("file://${testHelper.testDir}/assets/cube.glb");
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
await testHelper.capture(viewer, "load_glb_from_file");
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('load glb from buffer', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
var buffer = File("${testHelper.testDir}/cube.glb").readAsBytesSync();
|
||||
var model = await viewer.loadGlbFromBuffer(buffer);
|
||||
await viewer.transformToUnitCube(model);
|
||||
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 testHelper.capture(viewer, "load_glb_from_buffer");
|
||||
});
|
||||
|
||||
test('load glb from buffer with priority', () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.addDirectLight(DirectLight.sun());
|
||||
await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 3, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var buffer = File("${testHelper.testDir}/cube.glb").readAsBytesSync();
|
||||
var model1 = await viewer.loadGlbFromBuffer(buffer, priority: 7);
|
||||
var model2 = await viewer.loadGlbFromBuffer(buffer, priority: 0);
|
||||
|
||||
for (final entity in await viewer.getChildEntities(model1, true)) {
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
entity, "baseColorFactor", 0, 0, 0, 1.0, 1.0);
|
||||
}
|
||||
for (final entity in await viewer.getChildEntities(model2, true)) {
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
entity, "baseColorFactor", 0, 0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
await testHelper.capture(viewer, "load_glb_from_buffer_with_priority");
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -5,10 +5,12 @@ import 'package:image/image.dart' as img;
|
||||
import 'dart:typed_data';
|
||||
import 'package:ffi/ffi.dart';
|
||||
import 'package:image/image.dart';
|
||||
import 'package:thermion_dart/src/swift/swift_bindings.g.dart';
|
||||
import 'package:thermion_dart/src/utils/dart_resources.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/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;
|
||||
@@ -55,7 +57,6 @@ extension on Uri {
|
||||
String get name => pathSegments.where((e) => e != '').last;
|
||||
}
|
||||
|
||||
|
||||
Future<Uint8List> savePixelBufferToBmp(
|
||||
Uint8List pixelBuffer, int width, int height, String outputPath) async {
|
||||
var data = await pixelBufferToBmp(pixelBuffer, width, height);
|
||||
@@ -65,7 +66,7 @@ Future<Uint8List> savePixelBufferToBmp(
|
||||
}
|
||||
|
||||
class TestHelper {
|
||||
|
||||
late SwapChain swapChain;
|
||||
late Directory outDir;
|
||||
late String testDir;
|
||||
|
||||
@@ -76,19 +77,67 @@ class TestHelper {
|
||||
outDir = Directory("$testDir/output/${dir}");
|
||||
// outDir.deleteSync(recursive: true);
|
||||
outDir.createSync();
|
||||
DynamicLibrary.open('${testDir}/libThermionTextureSwift.dylib');
|
||||
|
||||
}
|
||||
|
||||
Future capture(ThermionViewer viewer, String outputFilename) async {
|
||||
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");
|
||||
var pixelBuffer = await viewer.capture();
|
||||
await savePixelBufferToBmp(
|
||||
pixelBuffer,
|
||||
viewer.viewportDimensions.$1.toInt(),
|
||||
viewer.viewportDimensions.$2.toInt(),
|
||||
outPath);
|
||||
var pixelBuffer = await viewer.capture(
|
||||
view: view,
|
||||
swapChain: swapChain ?? this.swapChain,
|
||||
renderTarget: renderTarget);
|
||||
view ??= await viewer.getViewAt(0);
|
||||
var vp = await view.getViewport();
|
||||
await savePixelBufferToBmp(pixelBuffer, vp.width, vp.height, outPath);
|
||||
return pixelBuffer;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
Future<ThermionViewer> createViewer(
|
||||
{img.Color? bg,
|
||||
Vector3? cameraPosition,
|
||||
viewportDimensions = (width: 500, height: 500)}) async {
|
||||
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;
|
||||
swapChain = await viewer.createHeadlessSwapChain(
|
||||
viewportDimensions.width, viewportDimensions.height);
|
||||
|
||||
await viewer.updateViewportAndCameraProjection(
|
||||
viewportDimensions.width.toDouble(),
|
||||
viewportDimensions.height.toDouble());
|
||||
if (bg != null) {
|
||||
await viewer.setBackgroundColor(
|
||||
bg.r.toDouble(), bg.g.toDouble(), bg.b.toDouble(), bg.a.toDouble());
|
||||
}
|
||||
|
||||
if (cameraPosition != null) {
|
||||
await viewer.setCameraPosition(
|
||||
cameraPosition.x, cameraPosition.y, cameraPosition.z);
|
||||
}
|
||||
return viewer;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Uint8List> pixelBufferToBmp(
|
||||
@@ -203,50 +252,6 @@ int _linearToSRGB(double linearValue) {
|
||||
}
|
||||
}
|
||||
|
||||
Future<ThermionViewer> createViewer(
|
||||
{img.Color? bg,
|
||||
Vector3? cameraPosition,
|
||||
viewportDimensions = (width: 500, height: 500)}) async {
|
||||
final packageUri = findPackageRoot('thermion_dart');
|
||||
|
||||
final lib = ThermionDartTexture1(DynamicLibrary.open(
|
||||
'${packageUri.toFilePath()}/native/lib/macos/swift/libthermion_swift.dylib'));
|
||||
final object = ThermionDartTexture.new1(lib);
|
||||
object.initWithWidth_height_(
|
||||
viewportDimensions.width, viewportDimensions.height);
|
||||
|
||||
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(viewportDimensions.width.toDouble(),
|
||||
viewportDimensions.height.toDouble());
|
||||
await viewer.createRenderTarget(viewportDimensions.width.toDouble(),
|
||||
viewportDimensions.height.toDouble(), object.metalTextureAddress);
|
||||
await viewer.updateViewportAndCameraProjection(
|
||||
viewportDimensions.width.toDouble(),
|
||||
viewportDimensions.height.toDouble());
|
||||
if (bg != null) {
|
||||
await viewer.setBackgroundColor(
|
||||
bg.r.toDouble(), bg.g.toDouble(), bg.b.toDouble(), bg.a.toDouble());
|
||||
}
|
||||
|
||||
if (cameraPosition != null) {
|
||||
await viewer.setCameraPosition(
|
||||
cameraPosition.x, cameraPosition.y, cameraPosition.z);
|
||||
}
|
||||
return viewer;
|
||||
}
|
||||
|
||||
Uint8List poissonBlend(List<Uint8List> textures, int width, int height) {
|
||||
final int numTextures = textures.length;
|
||||
final int size = width * height;
|
||||
|
||||
@@ -15,24 +15,22 @@ void main() async {
|
||||
|
||||
group('background', () {
|
||||
test('set background color to solid green', () async {
|
||||
var viewer = await createViewer();
|
||||
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 createViewer();
|
||||
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 createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundImage(
|
||||
"file:///${testHelper.testDir}/assets/cube_texture_512x512.png");
|
||||
await viewer.setPostProcessing(true);
|
||||
@@ -42,57 +40,11 @@ void main() async {
|
||||
});
|
||||
});
|
||||
|
||||
group("gltf", () {
|
||||
test('load glb from file', () async {
|
||||
var viewer = await createViewer();
|
||||
var model = await viewer.loadGlb("file://${testHelper.testDir}/cube.glb");
|
||||
await viewer.transformToUnitCube(model);
|
||||
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 testHelper.capture(viewer, "load_glb_from_file");
|
||||
});
|
||||
|
||||
test('load glb from buffer', () async {
|
||||
var viewer = await createViewer();
|
||||
var buffer = File("${testHelper.testDir}/cube.glb").readAsBytesSync();
|
||||
var model = await viewer.loadGlbFromBuffer(buffer);
|
||||
await viewer.transformToUnitCube(model);
|
||||
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 testHelper.capture(viewer, "load_glb_from_buffer");
|
||||
});
|
||||
|
||||
test('load glb from buffer with priority', () async {
|
||||
var viewer = await createViewer();
|
||||
await viewer.addDirectLight(DirectLight.sun());
|
||||
await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 3, 5);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -0.5));
|
||||
|
||||
var buffer = File("${testHelper.testDir}/cube.glb").readAsBytesSync();
|
||||
var model1 = await viewer.loadGlbFromBuffer(buffer, priority: 7);
|
||||
var model2 = await viewer.loadGlbFromBuffer(buffer, priority: 0);
|
||||
|
||||
for (final entity in await viewer.getChildEntities(model1, true)) {
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
entity, "baseColorFactor", 0, 0, 0, 1.0, 1.0);
|
||||
}
|
||||
for (final entity in await viewer.getChildEntities(model2, true)) {
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
entity, "baseColorFactor", 0, 0, 1.0, 0.0, 1.0);
|
||||
}
|
||||
await testHelper.capture(viewer, "load_glb_from_buffer_with_priority");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
group("scene update events", () {
|
||||
test('add light fires SceneUpdateEvent', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
var light = DirectLight(
|
||||
@@ -116,7 +68,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('remove light fires SceneUpdateEvent', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
var light = await viewer.addDirectLight(DirectLight.point());
|
||||
@@ -135,7 +87,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('add geometry fires SceneUpdateEvent', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
var geometry = GeometryHelper.cube();
|
||||
@@ -153,7 +105,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('remove geometry fires SceneUpdateEvent', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
var geometry = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final success = Completer<bool>();
|
||||
|
||||
@@ -171,7 +123,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('loadGlb fires SceneUpdateEvent', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final success = Completer<bool>();
|
||||
|
||||
@@ -191,7 +143,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('remove glb fires SceneUpdateEvent', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
final uri = "${testHelper.testDir}/cube.glb";
|
||||
var entity = await viewer.loadGlb(uri, keepData: false);
|
||||
|
||||
@@ -209,176 +161,10 @@ void main() async {
|
||||
});
|
||||
});
|
||||
|
||||
group("custom geometry", () {
|
||||
test('create cube (no uvs/normals)', () async {
|
||||
var viewer = await createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
|
||||
|
||||
await testHelper.capture(viewer, "geometry_cube_no_uv_no_normal");
|
||||
});
|
||||
|
||||
test('create cube (no normals)', () async {
|
||||
var viewer = await createViewer();
|
||||
var light = await viewer.addLight(
|
||||
LightType.POINT, 6500, 10000000, 0, 2, 0, 0, 0, 0,
|
||||
falloffRadius: 100.0);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.cube(normals: false, uvs: false));
|
||||
await testHelper.capture(viewer, "geometry_cube_no_normals");
|
||||
});
|
||||
|
||||
test('create cube (with normals)', () async {
|
||||
var viewer = await createViewer();
|
||||
|
||||
var light = await viewer.addLight(
|
||||
LightType.POINT, 6500, 10000000, 0, 2, 0, 0, 0, 0,
|
||||
falloffRadius: 100.0);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 1.0, 1.0, 1.0);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.cube(normals: true, uvs: false));
|
||||
await testHelper.capture(viewer, "geometry_cube_with_normals");
|
||||
});
|
||||
|
||||
test('create cube with custom ubershader material instance (color)',
|
||||
() async {
|
||||
var viewer = await createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
||||
|
||||
var materialInstance =
|
||||
await viewer.createUbershaderMaterialInstance(unlit: true);
|
||||
final cube = await viewer.createGeometry(
|
||||
GeometryHelper.cube(uvs: false, normals: true),
|
||||
materialInstance: materialInstance);
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 0.0);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_ubershader");
|
||||
await viewer.removeEntity(cube);
|
||||
await viewer.destroyMaterialInstance(materialInstance);
|
||||
});
|
||||
|
||||
test('create cube with custom ubershader material instance (texture)',
|
||||
() async {
|
||||
var viewer = await createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
|
||||
var materialInstance = await viewer.createUbershaderMaterialInstance();
|
||||
final cube = await viewer.createGeometry(
|
||||
GeometryHelper.cube(uvs: true, normals: true),
|
||||
materialInstance: materialInstance);
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync();
|
||||
var texture = await viewer.createTexture(textureData);
|
||||
await viewer.applyTexture(texture as ThermionFFITexture, cube);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_ubershader_texture");
|
||||
await viewer.removeEntity(cube);
|
||||
await viewer.destroyMaterialInstance(materialInstance);
|
||||
await viewer.destroyTexture(texture);
|
||||
});
|
||||
|
||||
test('unlit material with color only', () async {
|
||||
var viewer = await 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.createUnlitMaterialInstance();
|
||||
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_material_base_color");
|
||||
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('create cube with custom material instance (unlit)', () async {
|
||||
var viewer = await createViewer();
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
await viewer.setPostProcessing(true);
|
||||
await viewer.setToneMapping(ToneMapper.LINEAR);
|
||||
|
||||
var materialInstance = await viewer.createUnlitMaterialInstance();
|
||||
var cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync();
|
||||
var texture = await viewer.createTexture(textureData);
|
||||
await viewer.applyTexture(texture, cube);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_unlit_texture_only");
|
||||
await viewer.removeEntity(cube);
|
||||
|
||||
cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
// reusing same material instance, so set baseColorIndex to -1 to disable the texture
|
||||
await viewer.setMaterialPropertyInt(cube, "baseColorIndex", 0, -1);
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 1.0);
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_unlit_color_only");
|
||||
await viewer.removeEntity(cube);
|
||||
|
||||
cube = await viewer.createGeometry(GeometryHelper.cube(),
|
||||
materialInstance: materialInstance);
|
||||
// now set baseColorIndex to 0 to enable the texture and the base color
|
||||
await viewer.setMaterialPropertyInt(cube, "baseColorIndex", 0, 0);
|
||||
await viewer.setMaterialPropertyFloat4(
|
||||
cube, "baseColorFactor", 0, 0.0, 1.0, 0.0, 0.5);
|
||||
await viewer.applyTexture(texture, cube);
|
||||
|
||||
await testHelper.capture(
|
||||
viewer, "geometry_cube_with_custom_material_unlit_color_and_texture");
|
||||
|
||||
await viewer.removeEntity(cube);
|
||||
|
||||
await viewer.destroyTexture(texture);
|
||||
await viewer.destroyMaterialInstance(materialInstance);
|
||||
await viewer.dispose();
|
||||
});
|
||||
|
||||
test('create sphere (no normals)', () async {
|
||||
var viewer = await createViewer();
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer
|
||||
.createGeometry(GeometryHelper.sphere(normals: false, uvs: false));
|
||||
await testHelper.capture(viewer, "geometry_sphere_no_normals");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
group("MaterialInstance", () {
|
||||
test('disable depth write', () async {
|
||||
var viewer = await createViewer();
|
||||
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(
|
||||
@@ -467,7 +253,7 @@ void main() async {
|
||||
|
||||
group("materials", () {
|
||||
test('set float4 material property for custom geometry', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
@@ -482,7 +268,7 @@ void main() async {
|
||||
await testHelper.capture(viewer, "set_material_float4_post");
|
||||
});
|
||||
test('set float material property for custom geometry', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
@@ -500,7 +286,7 @@ void main() async {
|
||||
|
||||
test('set float material property (roughness) for custom geometry',
|
||||
() async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
@@ -522,7 +308,7 @@ void main() async {
|
||||
group("transforms & parenting", () {
|
||||
test('set multiple transforms simultaneously with setTransforms', () async {
|
||||
var viewer =
|
||||
await createViewer(bg: kRed, cameraPosition: Vector3(0, 0, 5));
|
||||
await testHelper.createViewer(bg: kRed, cameraPosition: Vector3(0, 0, 5));
|
||||
final cube1 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final cube2 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
@@ -534,14 +320,14 @@ void main() async {
|
||||
Matrix4.translation(Vector3(1, 0, 0))
|
||||
]);
|
||||
|
||||
await viewer.render();
|
||||
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 createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final cube = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
@@ -552,7 +338,7 @@ void main() async {
|
||||
test(
|
||||
'getParent returns the parent entity after one has been set via setParent',
|
||||
() async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final cube1 = await viewer.createGeometry(GeometryHelper.cube());
|
||||
|
||||
@@ -566,7 +352,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('getAncestor returns the ultimate parent entity', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
final grandparent = await viewer.createGeometry(GeometryHelper.cube());
|
||||
final parent = await viewer.createGeometry(GeometryHelper.cube());
|
||||
@@ -579,7 +365,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set position based on screenspace coord', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -591,7 +377,7 @@ void main() async {
|
||||
await viewer.queuePositionUpdateFromViewportCoords(cube, 0, 0);
|
||||
|
||||
// we need an explicit render call here to process the transform queue
|
||||
await viewer.render();
|
||||
await viewer.render(testHelper.swapChain);
|
||||
|
||||
await testHelper.capture(viewer, "set_position_from_viewport_coords");
|
||||
});
|
||||
@@ -599,7 +385,7 @@ void main() async {
|
||||
|
||||
group("layers & overlays", () {
|
||||
test('enable grid overlay', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(0, 0, 0, 1);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
@@ -612,7 +398,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('load glb from buffer with layer', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setBackgroundColor(1, 0, 1, 1);
|
||||
await viewer.setCameraPosition(0, 2, 5);
|
||||
@@ -629,7 +415,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('change layer visibility at runtime', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
await viewer.setBackgroundColor(1, 0, 1, 1);
|
||||
await viewer.setCameraPosition(0, 2, 5);
|
||||
@@ -719,7 +505,7 @@ void main() async {
|
||||
|
||||
group("stencil", () {
|
||||
test('set stencil highlight for glb', () async {
|
||||
final viewer = await createViewer();
|
||||
final viewer = await testHelper.createViewer();
|
||||
var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
await viewer.setPostProcessing(true);
|
||||
|
||||
@@ -736,7 +522,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for geometry', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -754,7 +540,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for gltf asset', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -774,7 +560,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for multiple geometry ', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -797,7 +583,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for multiple gltf assets ', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -824,7 +610,7 @@ void main() async {
|
||||
|
||||
group("texture", () {
|
||||
test("create/apply/dispose texture", () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync();
|
||||
@@ -861,21 +647,11 @@ void main() async {
|
||||
});
|
||||
});
|
||||
|
||||
group("render thread", () {
|
||||
test("request frame on render thread", () async {
|
||||
var viewer = await createViewer();
|
||||
viewer.requestFrame();
|
||||
|
||||
await Future.delayed(Duration(milliseconds: 20));
|
||||
await viewer.dispose();
|
||||
});
|
||||
});
|
||||
|
||||
// group("unproject", () {
|
||||
// test("unproject", () async {
|
||||
// final dimensions = (width: 1280, height: 768);
|
||||
|
||||
// var viewer = await createViewer(viewportDimensions: dimensions);
|
||||
// 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);
|
||||
|
||||
BIN
thermion_dart/test/libThermionTextureSwift.dylib
Normal file
BIN
thermion_dart/test/libThermionTextureSwift.dylib
Normal file
Binary file not shown.
@@ -15,7 +15,7 @@ void main() async {
|
||||
|
||||
group("texture tests", () {
|
||||
test('apply texture to custom ubershader material instance', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.addLight(LightType.SUN, 6500, 1000000, 0, 0, 0, 0, 0, -1);
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
@@ -38,7 +38,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('unlit material with color only', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -57,7 +57,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('create cube with custom material instance (unlit)', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setCameraPosition(0, 2, 6);
|
||||
await viewer
|
||||
.setCameraRotation(Quaternion.axisAngle(Vector3(1, 0, 0), -pi / 8));
|
||||
@@ -106,7 +106,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('create sphere (no normals)', () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(0.0, 0.0, 1.0, 1.0);
|
||||
await viewer.setCameraPosition(0, 0, 6);
|
||||
await viewer
|
||||
@@ -117,7 +117,7 @@ void main() async {
|
||||
|
||||
group("MaterialInstance", () {
|
||||
test('disable depth write', () async {
|
||||
var viewer = await createViewer();
|
||||
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(
|
||||
@@ -149,7 +149,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set uv scaling (unlit)', () async {
|
||||
var viewer = await createViewer();
|
||||
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(
|
||||
@@ -174,7 +174,7 @@ void main() async {
|
||||
|
||||
group("stencil", () {
|
||||
test('set stencil highlight for glb', () async {
|
||||
final viewer = await createViewer();
|
||||
final viewer = await testHelper.createViewer();
|
||||
var model = await viewer.loadGlb("${testHelper.testDir}/cube.glb", keepData: true);
|
||||
await viewer.setPostProcessing(true);
|
||||
|
||||
@@ -191,7 +191,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for geometry', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -209,7 +209,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for gltf asset', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -229,7 +229,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for multiple geometry ', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -252,7 +252,7 @@ void main() async {
|
||||
});
|
||||
|
||||
test('set stencil highlight for multiple gltf assets ', () async {
|
||||
var viewer = await createViewer();
|
||||
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);
|
||||
@@ -279,7 +279,7 @@ void main() async {
|
||||
|
||||
group("texture", () {
|
||||
test("create/apply/dispose texture", () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
|
||||
var textureData =
|
||||
File("${testHelper.testDir}/assets/cube_texture_512x512.png").readAsBytesSync();
|
||||
@@ -318,7 +318,7 @@ void main() async {
|
||||
|
||||
group("render thread", () {
|
||||
test("request frame on render thread", () async {
|
||||
var viewer = await createViewer();
|
||||
var viewer = await testHelper.createViewer();
|
||||
viewer.requestFrame();
|
||||
|
||||
await Future.delayed(Duration(milliseconds: 20));
|
||||
@@ -330,7 +330,7 @@ void main() async {
|
||||
// test("unproject", () async {
|
||||
// final dimensions = (width: 1280, height: 768);
|
||||
|
||||
// var viewer = await createViewer(viewportDimensions: dimensions);
|
||||
// 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);
|
||||
|
||||
33
thermion_dart/test/render_thread.dart
Normal file
33
thermion_dart/test/render_thread.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ffi';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'helpers.dart';
|
||||
|
||||
void main() async {
|
||||
final testHelper = TestHelper("render_thread");
|
||||
group("render thread/capture", () {
|
||||
test("request frame on render thread", () async {
|
||||
var viewer = await testHelper.createViewer();
|
||||
await viewer.setBackgroundColor(1.0, 0.0, 0.0, 1.0);
|
||||
|
||||
var texture = await testHelper.createTexture(500, 500);
|
||||
var renderTarget = await viewer.createRenderTarget(
|
||||
500, 500, texture.metalTextureAddress);
|
||||
|
||||
final view = await viewer.getViewAt(0);
|
||||
await view.setRenderTarget(renderTarget);
|
||||
|
||||
await viewer.render();
|
||||
|
||||
await Future.delayed(Duration(milliseconds: 1));
|
||||
|
||||
var data = texture.getTextureBytes()!;
|
||||
var pixels = data.bytes.cast<Uint8>().asTypedList(data.length);
|
||||
|
||||
savePixelBufferToBmp(
|
||||
pixels, 500, 500, "${testHelper.testDir}/request_frame.bmp");
|
||||
await viewer.dispose();
|
||||
});
|
||||
});
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user