Compare commits

..

16 Commits

Author SHA1 Message Date
Nick Fisher
cb517c907d chore(release): publish packages
- thermion_dart@0.2.1-dev.0.0.8
 - thermion_flutter_web@0.1.0+9
 - thermion_flutter@0.2.1-dev.7
 - thermion_flutter_platform_interface@0.2.1-dev.7
 - thermion_flutter_ffi@0.2.1-dev.7
2024-10-14 09:36:55 +08:00
Nick Fisher
a6f5e59cbb fix: move ThermionWin32.h to include 2024-10-14 09:36:28 +08:00
Nick Fisher
9420143a36 chore(release): publish packages
- thermion_dart@0.2.1-dev.0.0.7
 - thermion_flutter_web@0.1.0+8
 - thermion_flutter@0.2.1-dev.6
 - thermion_flutter_platform_interface@0.2.1-dev.6
 - thermion_flutter_ffi@0.2.1-dev.6
2024-10-14 09:25:59 +08:00
Nick Fisher
eb8835b63a Merge pull request #69 from nmfisher/feature/multiple_swapchains
Support multiple views/widgets/swapchains
2024-10-14 12:05:21 +11:00
Nick Fisher
f9468db266 Windows embedder fixes 2024-10-14 11:23:56 +11:00
Nick Fisher
1135ba054c cleanup 2024-10-12 15:07:14 +11:00
Nick Fisher
8f7509a23f cleanup 2024-10-12 15:06:57 +11:00
Nick Fisher
cba9ee98ad (flutter) set view renderable on Windows 2024-10-12 14:56:04 +11:00
Nick Fisher
0ec0fef8f3 move standalone Windows file to extras 2024-10-12 14:55:41 +11:00
Nick Fisher
a348562f56 cleanup 2024-10-12 14:36:51 +11:00
Nick Fisher
392a606bbc don't call endFrame() if no views were rendered 2024-10-12 14:36:05 +11:00
Nick Fisher
440bed4485 add files to run standalone Windows 2024-10-12 14:34:42 +11:00
Nick Fisher
a321966e5b fix Windows build.dart to avoid native_assets fork; add implementations for ThermionFlutterWindows 2024-10-12 02:14:37 +11:00
Nick Fisher
f180c1018f mobile gesture handler 2024-10-11 15:37:03 +08:00
Nick Fisher
f267aa6dc6 chore(release): publish packages
- thermion_dart@0.2.1-dev.0.0.6
 - thermion_flutter_web@0.1.0+7
 - thermion_flutter_platform_interface@0.2.1-dev.5
 - thermion_flutter@0.2.1-dev.5
 - thermion_flutter_ffi@0.2.1-dev.5
2024-10-10 20:58:19 +08:00
Nick Fisher
1c74e83c2c add native_assets_cli to dependencies 2024-10-10 20:57:50 +08:00
40 changed files with 1143 additions and 295 deletions

View File

@@ -3,6 +3,108 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## 2024-10-14
### 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.8`](#thermion_dart---v021-dev008)
- [`thermion_flutter_web` - `v0.1.0+9`](#thermion_flutter_web---v0109)
- [`thermion_flutter` - `v0.2.1-dev.7`](#thermion_flutter---v021-dev7)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.7`](#thermion_flutter_platform_interface---v021-dev7)
- [`thermion_flutter_ffi` - `v0.2.1-dev.7`](#thermion_flutter_ffi---v021-dev7)
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+9`
- `thermion_flutter` - `v0.2.1-dev.7`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.7`
- `thermion_flutter_ffi` - `v0.2.1-dev.7`
---
#### `thermion_dart` - `v0.2.1-dev.0.0.8`
- **FIX**: move ThermionWin32.h to include.
## 2024-10-14
### 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.7`](#thermion_dart---v021-dev007)
- [`thermion_flutter_web` - `v0.1.0+8`](#thermion_flutter_web---v0108)
- [`thermion_flutter` - `v0.2.1-dev.6`](#thermion_flutter---v021-dev6)
- [`thermion_flutter_platform_interface` - `v0.2.1-dev.6`](#thermion_flutter_platform_interface---v021-dev6)
- [`thermion_flutter_ffi` - `v0.2.1-dev.6`](#thermion_flutter_ffi---v021-dev6)
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+8`
- `thermion_flutter` - `v0.2.1-dev.6`
- `thermion_flutter_platform_interface` - `v0.2.1-dev.6`
- `thermion_flutter_ffi` - `v0.2.1-dev.6`
---
#### `thermion_dart` - `v0.2.1-dev.0.0.7`
- Bump "thermion_dart" to `0.2.1-dev.0.0.7`.
## 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 ## 2024-10-10
### Changes ### Changes

View File

@@ -1,5 +1,19 @@
## Android ## 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`: In release mode, you must add the following to your `app/build.gradle`:
``` ```

View File

@@ -1,3 +1,15 @@
## 0.2.1-dev.0.0.8
- **FIX**: move ThermionWin32.h to include.
## 0.2.1-dev.0.0.7
- Bump "thermion_dart" to `0.2.1-dev.0.0.7`.
## 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 ## 0.2.1-dev.0.0.5
- Bump "thermion_dart" to `0.2.1-dev.0.0.5`. - Bump "thermion_dart" to `0.2.1-dev.0.0.5`.

View 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
)

View 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

View 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

View File

@@ -32,19 +32,14 @@ void main(List<String> args) async {
final name = "thermion_dart.dart"; final name = "thermion_dart.dart";
final libUri = config.outputDirectory final libUri = config.outputDirectory
.resolve(config.targetOS.libraryFileName(name, linkMode)); .resolve(config.targetOS.libraryFileName(name, linkMode));
output.addAssets( output.addAsset(NativeCodeAsset(
[ package: config.packageName,
NativeCodeAsset( name: name,
package: config.packageName, file: libUri,
name: name, linkMode: linkMode,
file: libUri, os: config.targetOS,
linkMode: linkMode, architecture: config.dryRun ? null : config.targetArchitecture,
os: config.targetOS, ));
architecture: config.dryRun ? null : config.targetArchitecture,
)
],
linkInPackage: null,
);
return; return;
} }
@@ -58,7 +53,7 @@ void main(List<String> args) async {
.map((f) => f.path) .map((f) => f.path)
.toList(); .toList();
sources.addAll([ 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/image.c",
"${config.packageRoot.toFilePath()}/native/include/material/grid.c", "${config.packageRoot.toFilePath()}/native/include/material/grid.c",
"${config.packageRoot.toFilePath()}/native/include/material/unlit.c", "${config.packageRoot.toFilePath()}/native/include/material/unlit.c",
@@ -92,7 +87,6 @@ void main(List<String> args) async {
"basis_transcoder" "basis_transcoder"
]; ];
if (platform == "windows") { if (platform == "windows") {
libDir = Directory(libDir).uri.toFilePath(); libDir = Directory(libDir).uri.toFilePath();
libs = libs.map((lib) => "${libDir}${lib}.lib").toList(); libs = libs.map((lib) => "${libDir}${lib}.lib").toList();
@@ -118,7 +112,12 @@ void main(List<String> args) async {
defines["WIN32"] = "1"; defines["WIN32"] = "1";
defines["_DEBUG"] = "1"; defines["_DEBUG"] = "1";
defines["_DLL"] = "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") { if (platform == "ios") {
@@ -149,16 +148,26 @@ void main(List<String> args) async {
name: packageName, name: packageName,
language: Language.cpp, language: Language.cpp,
assetName: 'thermion_dart.dart', assetName: 'thermion_dart.dart',
sources: sources, sources: platform == "windows" ? [] : sources,
includes: ['native/include', 'native/include/filament'], includes: platform == "windows"
defines: defines, ? []
: ['native/include', 'native/include/filament'],
defines: platform == "windows" ? {} : defines,
flags: [ flags: [
if (platform == "macos") '-mmacosx-version-min=13.0', if (platform == "macos") '-mmacosx-version-min=13.0',
if (platform == "ios") '-mios-version-min=13.0', if (platform == "ios") '-mios-version-min=13.0',
...flags, ...flags,
...frameworks, ...frameworks,
...libs.map((lib) => "-l$lib"), if (platform != "windows") ...libs.map((lib) => "-l$lib"),
"-L$libDir", 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'], dartBuildFiles: ['hook/build.dart'],
); );
@@ -177,17 +186,24 @@ void main(List<String> args) async {
Architecture.ia32 => "i686-linux-android", Architecture.ia32 => "i686-linux-android",
_ => throw FormatException('Invalid') _ => throw FormatException('Invalid')
}; };
var compilerPath = config.cCompiler.compiler!.path; var compilerPath = config.cCompiler.compiler!.path;
if(Platform.isWindows && compilerPath.startsWith("/")) { if (Platform.isWindows && compilerPath.startsWith("/")) {
compilerPath = compilerPath.substring(1); compilerPath = compilerPath.substring(1);
} }
var ndkRoot = File(compilerPath).parent.parent.uri.toFilePath(windows:true);
var stlPath = var ndkRoot =
File([ndkRoot, "sysroot", "usr", "lib", archExtension, "libc++_shared.so"].join(Platform.pathSeparator)); 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( output.addAsset(NativeCodeAsset(
package: "thermion_dart", package: "thermion_dart",
name: "libc++_shared.so", name: "libc++_shared.so",
@@ -201,7 +217,7 @@ void main(List<String> args) async {
if (config.targetOS == "windows") { if (config.targetOS == "windows") {
output.addAsset( output.addAsset(
NativeCodeAsset( NativeCodeAsset(
package: "thermion_dart", package: config.packageName,
name: "thermion_dart.dll", name: "thermion_dart.dll",
linkMode: DynamicLoadingBundled(), linkMode: DynamicLoadingBundled(),
os: config.targetOS, os: config.targetOS,

View File

@@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:math';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:vector_math/vector_math_64.dart'; import 'package:vector_math/vector_math_64.dart';
@@ -26,6 +27,8 @@ class DelegateInputHandler implements InputHandler {
Map<InputType, InputAction> _actions = { Map<InputType, InputAction> _actions = {
InputType.LMB_HOLD_AND_MOVE: InputAction.TRANSLATE, InputType.LMB_HOLD_AND_MOVE: InputAction.TRANSLATE,
InputType.SCALE1: InputAction.TRANSLATE,
InputType.SCALE2: InputAction.ZOOM,
InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE, InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE,
InputType.SCROLLWHEEL: InputAction.TRANSLATE, InputType.SCROLLWHEEL: InputAction.TRANSLATE,
InputType.POINTER_MOVE: InputAction.NONE, InputType.POINTER_MOVE: InputAction.NONE,
@@ -99,6 +102,8 @@ class DelegateInputHandler implements InputHandler {
InputType.KEYDOWN_W: InputAction.TRANSLATE, InputType.KEYDOWN_W: InputAction.TRANSLATE,
InputType.KEYDOWN_S: InputAction.TRANSLATE, InputType.KEYDOWN_S: InputAction.TRANSLATE,
InputType.KEYDOWN_D: InputAction.TRANSLATE, InputType.KEYDOWN_D: InputAction.TRANSLATE,
InputType.SCALE1: InputAction.TRANSLATE,
InputType.SCALE2: InputAction.ZOOM,
if (freeLook) InputType.POINTER_MOVE: InputAction.ROTATE, if (freeLook) InputType.POINTER_MOVE: InputAction.ROTATE,
}); });
@@ -235,15 +240,6 @@ class DelegateInputHandler implements InputHandler {
@override @override
Future<bool> get initialized => viewer.initialized; Future<bool> get initialized => viewer.initialized;
@override
Future<void> onScaleEnd() async {}
@override
Future<void> onScaleStart() async {}
@override
Future<void> onScaleUpdate() async {}
@override @override
void setActionForType(InputType gestureType, InputAction gestureAction) { void setActionForType(InputType gestureType, InputAction gestureAction) {
_actions[gestureType] = gestureAction; _actions[gestureType] = gestureAction;
@@ -261,4 +257,26 @@ class DelegateInputHandler implements InputHandler {
void keyUp(PhysicalKey key) { void keyUp(PhysicalKey key) {
_pressedKeys.remove(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");
}
}
} }

View File

@@ -35,9 +35,9 @@ abstract class InputHandler {
Future<void> onPointerMove( Future<void> onPointerMove(
Vector2 localPosition, Vector2 delta, bool isMiddle); Vector2 localPosition, Vector2 delta, bool isMiddle);
Future<void> onPointerUp(bool isMiddle); Future<void> onPointerUp(bool isMiddle);
Future<void> onScaleStart(); Future<void> onScaleStart(Vector2 focalPoint, int pointerCount);
Future<void> onScaleUpdate(); Future<void> onScaleUpdate(Vector2 focalPoint, Vector2 focalPointDelta, double horizontalScale, double verticalScale, double scale, int pointerCount);
Future<void> onScaleEnd(); Future<void> onScaleEnd(int pointerCount);
Future<bool> get initialized; Future<bool> get initialized;
Future dispose(); Future dispose();

View File

@@ -142,6 +142,17 @@ external void Viewer_setViewRenderable(
bool renderable, bool renderable,
); );
@ffi.Native<
ffi.Void Function(ffi.Pointer<TViewer>, ffi.Pointer<ffi.Char>, ffi.Float,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void Viewer_loadIblRenderThread(
ffi.Pointer<TViewer> viewer,
ffi.Pointer<ffi.Char> iblPath,
double intensity,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@ffi.Native< @ffi.Native<
ffi.Void Function( ffi.Void Function(
ffi.Pointer<TViewer>, ffi.Pointer<TViewer>,

View File

@@ -360,7 +360,12 @@ class ThermionViewerFFI extends ThermionViewer {
Future loadIbl(String lightingPath, {double intensity = 30000}) async { Future loadIbl(String lightingPath, {double intensity = 30000}) async {
final pathPtr = final pathPtr =
lightingPath.toNativeUtf8(allocator: allocator).cast<Char>(); lightingPath.toNativeUtf8(allocator: allocator).cast<Char>();
load_ibl(_viewer!, pathPtr, intensity);
await withVoidCallback((cb) {
Viewer_loadIblRenderThread(_viewer!, pathPtr, intensity, cb);
});
} }
/// ///

View File

@@ -21,14 +21,14 @@ extern "C"
typedef struct TScene TScene; typedef struct TScene TScene;
struct TMaterialKey { struct TMaterialKey {
bool doubleSided = 1; bool doubleSided = true;
bool unlit = 1; bool unlit = true;
bool hasVertexColors = 1; bool hasVertexColors = true;
bool hasBaseColorTexture = 1; bool hasBaseColorTexture = true;
bool hasNormalTexture = 1; bool hasNormalTexture = true;
bool hasOcclusionTexture = 1; bool hasOcclusionTexture = true;
bool hasEmissiveTexture = 1; bool hasEmissiveTexture = true;
bool useSpecularGlossiness = 1; bool useSpecularGlossiness = true;
int alphaMode = 4; int alphaMode = 4;
bool enableDiagnostics = 4; bool enableDiagnostics = 4;
union { union {
@@ -43,42 +43,42 @@ extern "C"
}; };
#else #else
struct { struct {
bool hasMetallicRoughnessTexture = 1; bool hasMetallicRoughnessTexture = true;
uint8_t metallicRoughnessUV = 7; uint8_t metallicRoughnessUV = 7;
}; };
struct { struct {
bool hasSpecularGlossinessTexture = 1; bool hasSpecularGlossinessTexture = true;
uint8_t specularGlossinessUV = 7; uint8_t specularGlossinessUV = 7;
}; };
#endif #endif
}; };
uint8_t baseColorUV; uint8_t baseColorUV;
// -- 32 bit boundary -- // -- 32 bit boundary --
bool hasClearCoatTexture = 1; bool hasClearCoatTexture = true;
uint8_t clearCoatUV = 7; uint8_t clearCoatUV = 7;
bool hasClearCoatRoughnessTexture = 1; bool hasClearCoatRoughnessTexture = true;
uint8_t clearCoatRoughnessUV = 7; uint8_t clearCoatRoughnessUV = 7;
bool hasClearCoatNormalTexture = 1; bool hasClearCoatNormalTexture = true;
uint8_t clearCoatNormalUV = 7; uint8_t clearCoatNormalUV = 7;
bool hasClearCoat = 1; bool hasClearCoat = true;
bool hasTransmission = 1; bool hasTransmission = true;
bool hasTextureTransforms = 6; bool hasTextureTransforms = 6;
// -- 32 bit boundary -- // -- 32 bit boundary --
uint8_t emissiveUV; uint8_t emissiveUV;
uint8_t aoUV; uint8_t aoUV;
uint8_t normalUV; uint8_t normalUV;
bool hasTransmissionTexture = 1; bool hasTransmissionTexture = true;
uint8_t transmissionUV = 7; uint8_t transmissionUV = 7;
// -- 32 bit boundary -- // -- 32 bit boundary --
bool hasSheenColorTexture = 1; bool hasSheenColorTexture = true;
uint8_t sheenColorUV = 7; uint8_t sheenColorUV = 7;
bool hasSheenRoughnessTexture = 1; bool hasSheenRoughnessTexture = true;
uint8_t sheenRoughnessUV = 7; uint8_t sheenRoughnessUV = 7;
bool hasVolumeThicknessTexture = 1; bool hasVolumeThicknessTexture = true;
uint8_t volumeThicknessUV = 7; uint8_t volumeThicknessUV = 7;
bool hasSheen = 1; bool hasSheen = true;
bool hasIOR = 1; bool hasIOR = true;
bool hasVolume = 1; bool hasVolume = true;
} ; } ;
typedef struct TMaterialKey TMaterialKey; typedef struct TMaterialKey TMaterialKey;

View File

@@ -99,7 +99,7 @@ extern "C"
EMSCRIPTEN_KEEPALIVE void load_skybox(TViewer *viewer, const char *skyboxPath); 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 create_ibl(TViewer *viewer, float r, float g, float b, float intensity);
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix); EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix);
EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void remove_skybox(TViewer *viewer);

View File

@@ -19,7 +19,7 @@ extern "C"
typedef int32_t EntityId; typedef int32_t EntityId;
typedef void (*FilamentRenderCallback)(void *const owner); typedef void (*FilamentRenderCallback)(void *const owner);
void Viewer_createOnRenderThread( EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
void *const context, void *const context,
void *const platform, void *const platform,
const char *uberArchivePath, const char *uberArchivePath,
@@ -27,68 +27,68 @@ extern "C"
void (*renderCallback)(void *const renderCallbackOwner), void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner, void *const renderCallbackOwner,
void (*callback)(TViewer *viewer)); void (*callback)(TViewer *viewer));
void Viewer_createSwapChainRenderThread(TViewer *viewer, void *const surface, void (*onComplete)(TSwapChain*)); EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer, void *const surface, void (*onComplete)(TSwapChain*));
void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, uint32_t width, uint32_t height, void (*onComplete)(TSwapChain*)); EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, uint32_t width, uint32_t height, void (*onComplete)(TSwapChain*));
void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain* swapChain, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain* swapChain, void (*onComplete)());
void Viewer_renderRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain); EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain);
void Viewer_captureRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, uint8_t* out, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, uint8_t* out, void (*onComplete)());
void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, TRenderTarget* renderTarget, uint8_t* out, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView* view, TSwapChain* swapChain, TRenderTarget* renderTarget, uint8_t* out, void (*onComplete)());
void Viewer_requestFrameRenderThread(TViewer *viewer, 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)());
void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping); EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping);
void View_setBloomRenderThread(TView *tView, double bloom); EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom);
void destroy_filament_viewer_render_thread(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(TViewer *viewer);
FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback); FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
void set_rendering_render_thread(TViewer *viewer, bool rendering, void(*onComplete)()); EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void(*onComplete)());
void set_frame_interval_render_thread(TViewer *viewer, float frameInterval); EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a); EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
void clear_background_image_render_thread(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp); EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)()); EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
void remove_skybox_render_thread(TViewer *viewer); EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer);
void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync, void (*callback)(EntityId)); EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, bool loadResourcesAsync, void (*callback)(EntityId));
void load_glb_render_thread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId)); EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(TSceneManager *sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
void load_gltf_render_thread(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId)); EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(TSceneManager *sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
void create_instance_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)(EntityId)); EMSCRIPTEN_KEEPALIVE void create_instance_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)(EntityId));
void remove_entity_render_thread(TViewer *viewer, EntityId asset, void (*callback)()); EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer, EntityId asset, void (*callback)());
void clear_entities_render_thread(TViewer *viewer, void (*callback)()); EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)());
void apply_weights_render_thread( EMSCRIPTEN_KEEPALIVE void apply_weights_render_thread(
TSceneManager *sceneManager, TSceneManager *sceneManager,
EntityId asset, EntityId asset,
const char *const entityName, const char *const entityName,
float *const weights, float *const weights,
int count); int count);
void set_animation_frame_render_thread(TSceneManager *sceneManager, EntityId asset, int animationIndex, int animationFrame); EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(TSceneManager *sceneManager, EntityId asset, int animationIndex, int animationFrame);
void stop_animation_render_thread(TSceneManager *sceneManager, EntityId asset, int index); EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(TSceneManager *sceneManager, EntityId asset, int index);
void get_animation_count_render_thread(TSceneManager *sceneManager, EntityId asset, void (*callback)(int)); EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(TSceneManager *sceneManager, EntityId asset, void (*callback)(int));
void get_animation_name_render_thread(TSceneManager *sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)()); EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(TSceneManager *sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
void get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)()); EMSCRIPTEN_KEEPALIVE void get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
void get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t)); EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
void set_morph_target_weights_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(TSceneManager *sceneManager,
EntityId asset, EntityId asset,
const float *const morphData, const float *const morphData,
int numWeights, int numWeights,
void (*callback)(bool)); void (*callback)(bool));
void update_bone_matrices_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(TSceneManager *sceneManager,
EntityId asset, void(*callback)(bool)); EntityId asset, void(*callback)(bool));
void set_bone_transform_render_thread( EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
TSceneManager *sceneManager, TSceneManager *sceneManager,
EntityId asset, EntityId asset,
int skinIndex, int skinIndex,
int boneIndex, int boneIndex,
const float *const transform, const float *const transform,
void (*callback)(bool)); void (*callback)(bool));
void set_post_processing_render_thread(TViewer *viewer, bool enabled); EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer, bool enabled);
void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void(*callback)()); EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void(*callback)());
void create_geometry_render_thread( EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
TSceneManager *sceneManager, TSceneManager *sceneManager,
float *vertices, float *vertices,
int numVertices, int numVertices,
@@ -102,7 +102,7 @@ extern "C"
TMaterialInstance *materialInstance, TMaterialInstance *materialInstance,
bool keepData, bool keepData,
void (*callback)(EntityId)); void (*callback)(EntityId));
void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)()); EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)());
#ifdef __cplusplus #ifdef __cplusplus

View 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")

View File

@@ -767,7 +767,7 @@ namespace thermion
// bloom can be a bit glitchy (some Intel iGPUs won't render when postprocessing is enabled and bloom is disabled, // bloom can be a bit glitchy (some Intel iGPUs won't render when postprocessing is enabled and bloom is disabled,
// and render targets on MacOS flicker when bloom is disabled. // and render targets on MacOS flicker when bloom is disabled.
// Here, we enable bloom, but set to 0 strength // Here, we enable bloom, but set to 0 strength
view->setBloomOptions({.enabled=true, .strength = 0}); view->setBloomOptions({.strength = 0, .enabled=true });
view->setShadowingEnabled(false); view->setShadowingEnabled(false);
view->setScreenSpaceRefractionEnabled(false); view->setScreenSpaceRefractionEnabled(false);
view->setPostProcessingEnabled(false); view->setPostProcessingEnabled(false);
@@ -1051,8 +1051,8 @@ namespace thermion
_renderer->render(view); _renderer->render(view);
} }
} }
_renderer->endFrame();
} }
_renderer->endFrame();
} }
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
_engine->execute(); _engine->execute();

View File

@@ -1,3 +1,8 @@
#ifdef _WIN32
#define _USE_MATH_DEFINES
#include <cmath>
#endif
#include "GridOverlay.hpp" #include "GridOverlay.hpp"
#include <filament/Engine.h> #include <filament/Engine.h>

View File

@@ -1,14 +1,7 @@
#ifdef _WIN32 #ifdef _WIN32
#pragma comment(lib, "Shlwapi.lib") #include "ThermionWin32.h"
#pragma comment(lib, "opengl32.lib")
#endif #endif
#include "ResourceBuffer.hpp"
#include "FilamentViewer.hpp"
#include "filament/LightManager.h"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include <thread> #include <thread>
#include <functional> #include <functional>
@@ -16,6 +9,12 @@
#include <emscripten/emscripten.h> #include <emscripten/emscripten.h>
#endif #endif
#include "filament/LightManager.h"
#include "ResourceBuffer.hpp"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
using namespace thermion; using namespace thermion;
extern "C" extern "C"
@@ -93,7 +92,7 @@ extern "C"
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity); ((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); ((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
} }
@@ -230,62 +229,62 @@ extern "C"
return reinterpret_cast<TCamera *>(filamentCamera); 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(); const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
return convert_mat4_to_double4x4(mat); 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(); const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
return convert_mat4_to_double4x4(mat); 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(); const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
return convert_mat4_to_double4x4(mat); 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(); const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
return convert_mat4_to_double4x4(mat); 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); auto cam = reinterpret_cast<filament::Camera *>(camera);
const auto &mat = convert_double4x4_to_mat4(matrix); const auto &mat = convert_double4x4_to_mat4(matrix);
cam->setCustomProjection(mat, near, far); 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); auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setLensProjection(focalLength, aspect, near, far); 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); auto cam = reinterpret_cast<filament::Camera *>(camera);
cam->setModelMatrix(convert_double4x4_to_mat4(matrix)); 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); auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getNear(); 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); auto cam = reinterpret_cast<filament::Camera *>(camera);
return cam->getCullingFar(); 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(); const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
@@ -304,7 +303,6 @@ extern "C"
return array; return array;
} }
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance) EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
{ {
@@ -703,8 +701,9 @@ extern "C"
EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *tSceneManager, EntityId *entities, const double *const transforms, int numEntities) EMSCRIPTEN_KEEPALIVE void SceneManager_queueTransformUpdates(TSceneManager *tSceneManager, EntityId *entities, const double *const transforms, int numEntities)
{ {
auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager); auto *sceneManager = reinterpret_cast<SceneManager *>(tSceneManager);
math::mat4 matrices[
numEntities]; std::vector<math::mat4> matrices(
numEntities);
for (int i = 0; i < numEntities; i++) for (int i = 0; i < numEntities; i++)
{ {
matrices[i] = math::mat4( matrices[i] = math::mat4(
@@ -723,7 +722,7 @@ extern "C"
transforms[i * 16 + 14], transforms[i * 16 + 14],
transforms[i * 16 + 15]); 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) EMSCRIPTEN_KEEPALIVE bool update_bone_matrices(TSceneManager *sceneManager, EntityId entityId)
@@ -955,10 +954,10 @@ extern "C"
EMSCRIPTEN_KEEPALIVE void set_material_property_float4(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, double4 value) EMSCRIPTEN_KEEPALIVE void set_material_property_float4(TSceneManager *sceneManager, EntityId entity, int materialIndex, const char *property, double4 value)
{ {
filament::math::float4 filamentValue; filament::math::float4 filamentValue;
filamentValue.x = static_cast<float32_t>(value.x); filamentValue.x = static_cast<float>(value.x);
filamentValue.y = static_cast<float32_t>(value.y); filamentValue.y = static_cast<float>(value.y);
filamentValue.z = static_cast<float32_t>(value.z); filamentValue.z = static_cast<float>(value.z);
filamentValue.w = static_cast<float32_t>(value.w); filamentValue.w = static_cast<float>(value.w);
((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, filamentValue); ((SceneManager *)sceneManager)->setMaterialProperty(entity, materialIndex, property, filamentValue);
} }

View File

@@ -184,7 +184,7 @@ extern "C"
static RenderLoop *_rl; static RenderLoop *_rl;
void Viewer_createOnRenderThread( EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
void *const context, void *const platform, const char *uberArchivePath, void *const context, void *const platform, const char *uberArchivePath,
const void *const loader, const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner), void (*renderCallback)(void *const renderCallbackOwner),
@@ -200,14 +200,14 @@ extern "C"
renderCallback, renderCallbackOwner, callback); renderCallback, renderCallbackOwner, callback);
} }
void destroy_filament_viewer_render_thread(TViewer *viewer) EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(TViewer *viewer)
{ {
_rl->destroyViewer((FilamentViewer *)viewer); _rl->destroyViewer((FilamentViewer *)viewer);
delete _rl; delete _rl;
_rl = nullptr; _rl = nullptr;
} }
void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer,
uint32_t width, uint32_t width,
uint32_t height, uint32_t height,
void (*onComplete)(TSwapChain*)) void (*onComplete)(TSwapChain*))
@@ -221,7 +221,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void Viewer_createSwapChainRenderThread(TViewer *viewer, EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer,
void *const surface, void *const surface,
void (*onComplete)(TSwapChain*)) void (*onComplete)(TSwapChain*))
{ {
@@ -234,7 +234,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)()) EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)())
{ {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
[=]() mutable [=]() mutable
@@ -246,7 +246,7 @@ extern "C"
} }
void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)()) EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void(*onComplete)())
{ {
if (!_rl) if (!_rl)
{ {
@@ -258,7 +258,17 @@ extern "C"
} }
} }
void 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) set_frame_interval_render_thread(TViewer *viewer, float frameIntervalInMilliseconds)
{ {
_rl->setFrameIntervalInMilliseconds(frameIntervalInMilliseconds); _rl->setFrameIntervalInMilliseconds(frameIntervalInMilliseconds);
@@ -267,7 +277,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void Viewer_renderRenderThread(TViewer *viewer, TView *tView, TSwapChain *tSwapChain) EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *tView, TSwapChain *tSwapChain)
{ {
std::packaged_task<void()> lambda([=]() mutable std::packaged_task<void()> lambda([=]() mutable
{ {
@@ -276,21 +286,21 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void Viewer_captureRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, 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 std::packaged_task<void()> lambda([=]() mutable
{ Viewer_capture(viewer, view, tSwapChain, pixelBuffer, onComplete); }); { Viewer_capture(viewer, view, tSwapChain, pixelBuffer, onComplete); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget* tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)()) EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget* tRenderTarget, uint8_t *pixelBuffer, void (*onComplete)())
{ {
std::packaged_task<void()> lambda([=]() mutable std::packaged_task<void()> lambda([=]() mutable
{ Viewer_captureRenderTarget(viewer, view, tSwapChain, tRenderTarget, pixelBuffer, onComplete); }); { Viewer_captureRenderTarget(viewer, view, tSwapChain, tRenderTarget, pixelBuffer, onComplete); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void EMSCRIPTEN_KEEPALIVE void
set_background_color_render_thread(TViewer *viewer, const float r, const float g, set_background_color_render_thread(TViewer *viewer, const float r, const float g,
const float b, const float a) const float b, const float a)
{ {
@@ -300,7 +310,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void load_gltf_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(TSceneManager *sceneManager,
const char *path, const char *path,
const char *relativeResourcePath, const char *relativeResourcePath,
bool keepData, bool keepData,
@@ -314,7 +324,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void load_glb_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(TSceneManager *sceneManager,
const char *path, const char *path,
int numInstances, int numInstances,
bool keepData, bool keepData,
@@ -330,7 +340,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void SceneManager_loadGlbFromBufferRenderThread(TSceneManager *sceneManager,
const uint8_t *const data, const uint8_t *const data,
size_t length, size_t length,
int numInstances, int numInstances,
@@ -350,14 +360,14 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void clear_background_image_render_thread(TViewer *viewer) EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer)
{ {
std::packaged_task<void()> lambda([=] std::packaged_task<void()> lambda([=]
{ clear_background_image(viewer); }); { clear_background_image(viewer); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void set_background_image_render_thread(TViewer *viewer, EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer,
const char *path, const char *path,
bool fillHeight, void (*callback)()) bool fillHeight, void (*callback)())
{ {
@@ -369,7 +379,8 @@ extern "C"
}); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void set_background_image_position_render_thread(TViewer *viewer,
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer,
float x, float y, float x, float y,
bool clamp) bool clamp)
{ {
@@ -379,7 +390,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void load_skybox_render_thread(TViewer *viewer, EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(TViewer *viewer,
const char *skyboxPath, const char *skyboxPath,
void (*onComplete)()) void (*onComplete)())
{ {
@@ -390,30 +401,22 @@ extern "C"
}); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void load_ibl_render_thread(TViewer *viewer, const char *iblPath, EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(TViewer *viewer)
float intensity)
{
std::packaged_task<void()> lambda(
[=]
{ load_ibl(viewer, iblPath, intensity); });
auto fut = _rl->add_task(lambda);
}
void remove_skybox_render_thread(TViewer *viewer)
{ {
std::packaged_task<void()> lambda([=] std::packaged_task<void()> lambda([=]
{ remove_skybox(viewer); }); { remove_skybox(viewer); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void remove_ibl_render_thread(TViewer *viewer) EMSCRIPTEN_KEEPALIVE void remove_ibl_render_thread(TViewer *viewer)
{ {
std::packaged_task<void()> lambda([=] std::packaged_task<void()> lambda([=]
{ remove_ibl(viewer); }); { remove_ibl(viewer); });
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void remove_entity_render_thread(TViewer *viewer, EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(TViewer *viewer,
EntityId asset, void (*callback)()) EntityId asset, void (*callback)())
{ {
std::packaged_task<void()> lambda([=] std::packaged_task<void()> lambda([=]
@@ -424,7 +427,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void clear_entities_render_thread(TViewer *viewer, void (*callback)()) EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(TViewer *viewer, void (*callback)())
{ {
std::packaged_task<void()> lambda([=] std::packaged_task<void()> lambda([=]
{ {
@@ -435,7 +438,7 @@ extern "C"
} }
void EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity, get_morph_target_name_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
EntityId childEntity, char *const outPtr, int index, void (*callback)()) EntityId childEntity, char *const outPtr, int index, void (*callback)())
{ {
@@ -447,7 +450,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId assetEntity, get_morph_target_name_count_render_thread(TSceneManager *sceneManager, EntityId assetEntity,
EntityId childEntity, void (*callback)(int)) EntityId childEntity, void (*callback)(int))
{ {
@@ -459,7 +462,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void set_animation_frame_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(TSceneManager *sceneManager,
EntityId asset, EntityId asset,
int animationIndex, int animationIndex,
int animationFrame) int animationFrame)
@@ -469,7 +472,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void stop_animation_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(TSceneManager *sceneManager,
EntityId asset, int index) EntityId asset, int index)
{ {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
@@ -478,7 +481,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void get_animation_count_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(TSceneManager *sceneManager,
EntityId asset, EntityId asset,
void (*callback)(int)) void (*callback)(int))
{ {
@@ -492,7 +495,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void get_animation_name_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(TSceneManager *sceneManager,
EntityId asset, EntityId asset,
char *const outPtr, char *const outPtr,
int index, int index,
@@ -507,7 +510,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void EMSCRIPTEN_KEEPALIVE void
get_name_for_entity_render_thread(TSceneManager *sceneManager, const EntityId entityId, void (*callback)(const char *)) get_name_for_entity_render_thread(TSceneManager *sceneManager, const EntityId entityId, void (*callback)(const char *))
{ {
std::packaged_task<const char *()> lambda( std::packaged_task<const char *()> lambda(
@@ -520,7 +523,7 @@ extern "C"
auto fut = _rl->add_task(lambda); 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, EntityId asset,
const float *const morphData, const float *const morphData,
int numWeights, int numWeights,
@@ -535,7 +538,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void set_bone_transform_render_thread( EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
TSceneManager *sceneManager, TSceneManager *sceneManager,
EntityId asset, EntityId asset,
int skinIndex, int skinIndex,
@@ -553,7 +556,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void update_bone_matrices_render_thread(TSceneManager *sceneManager, EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(TSceneManager *sceneManager,
EntityId entity, void (*callback)(bool)) EntityId entity, void (*callback)(bool))
{ {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
@@ -565,7 +568,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping) { EMSCRIPTEN_KEEPALIVE void View_setToneMappingRenderThread(TView *tView, TEngine *tEngine, thermion::ToneMapping toneMapping) {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
[=] [=]
{ {
@@ -574,7 +577,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void View_setBloomRenderThread(TView *tView, double bloom) { EMSCRIPTEN_KEEPALIVE void View_setBloomRenderThread(TView *tView, double bloom) {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
[=] [=]
{ {
@@ -583,7 +586,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)()) EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)())
{ {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
[=] [=]
@@ -594,7 +597,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void create_geometry_render_thread( EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
TSceneManager *sceneManager, TSceneManager *sceneManager,
float *vertices, float *vertices,
int numVertices, int numVertices,
@@ -619,7 +622,7 @@ extern "C"
auto fut = _rl->add_task(lambda); auto fut = _rl->add_task(lambda);
} }
void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)()) EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(TViewer* viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
{ {
std::packaged_task<void()> lambda( std::packaged_task<void()> lambda(
[=] [=]

View File

@@ -177,6 +177,8 @@ namespace filament
case Mode::ORBIT: case Mode::ORBIT:
return new OrbitManipulator<FLOAT>(mode, details); return new OrbitManipulator<FLOAT>(mode, details);
} }
// just to make MSVC happy
return new OrbitManipulator<FLOAT>(mode, details);
} }
template <typename FLOAT> template <typename FLOAT>

View File

@@ -1,6 +1,6 @@
name: thermion_dart name: thermion_dart
description: 3D rendering toolkit for Dart. description: 3D rendering toolkit for Dart.
version: 0.2.1-dev.0.0.5 version: 0.2.1-dev.0.0.8
homepage: https://thermion.dev homepage: https://thermion.dev
repository: https://github.com/nmfisher/thermion repository: https://github.com/nmfisher/thermion
@@ -13,6 +13,7 @@ dependencies:
ffi: ^2.1.2 ffi: ^2.1.2
animation_tools_dart: ^0.1.0 animation_tools_dart: ^0.1.0
native_toolchain_c: ^0.4.2 native_toolchain_c: ^0.4.2
native_assets_cli: ^0.6.1
archive: ^3.6.1 archive: ^3.6.1
web: ^1.0.0 web: ^1.0.0
logging: ^1.2.0 logging: ^1.2.0

View File

@@ -1,3 +1,15 @@
## 0.2.1-dev.7
- Update a dependency to the latest release.
## 0.2.1-dev.6
- Update a dependency to the latest release.
## 0.2.1-dev.5
- Update a dependency to the latest release.
## 0.2.1-dev.4 ## 0.2.1-dev.4
- Update a dependency to the latest release. - Update a dependency to the latest release.

View File

@@ -110,7 +110,7 @@ class _ThermionListenerWidgetState extends State<ThermionListenerWidget> {
Widget _mobile(double pixelRatio) { Widget _mobile(double pixelRatio) {
return _MobileListenerWidget( return _MobileListenerWidget(
gestureHandler: widget.gestureHandler, pixelRatio: pixelRatio); gestureHandler: widget.gestureHandler, pixelRatio: pixelRatio, child:widget.child);
} }
@override @override
@@ -135,8 +135,10 @@ class _ThermionListenerWidgetState extends State<ThermionListenerWidget> {
class _MobileListenerWidget extends StatefulWidget { class _MobileListenerWidget extends StatefulWidget {
final InputHandler gestureHandler; final InputHandler gestureHandler;
final double pixelRatio; final double pixelRatio;
final Widget? child;
const _MobileListenerWidget({Key? key, required this.gestureHandler, required this.pixelRatio}) const _MobileListenerWidget(
{Key? key, required this.gestureHandler, required this.pixelRatio, this.child})
: super(key: key); : super(key: key);
@override @override
@@ -154,22 +156,29 @@ class _MobileListenerWidgetState extends State<_MobileListenerWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onTapDown: (details) => widget.gestureHandler onTapDown: (details) => widget.gestureHandler.onPointerDown(
.onPointerDown(details.localPosition.toVector2() * widget.pixelRatio, false), details.localPosition.toVector2() * widget.pixelRatio, false),
onDoubleTap: () { onDoubleTap: () {
widget.gestureHandler.setActionForType(InputType.SCALE1, widget.gestureHandler.setActionForType(InputType.SCALE1,
isPan ? InputAction.TRANSLATE : InputAction.ROTATE); isPan ? InputAction.TRANSLATE : InputAction.ROTATE);
}, },
onScaleStart: (details) async { onScaleStart: (details) async {
await widget.gestureHandler.onScaleStart(); await widget.gestureHandler.onScaleStart(
}, details.localFocalPoint.toVector2(), details.pointerCount);
onScaleUpdate: (details) async { },
await widget.gestureHandler.onScaleUpdate(); onScaleUpdate: (ScaleUpdateDetails details) async {
}, await widget.gestureHandler.onScaleUpdate(
onScaleEnd: (details) async { details.localFocalPoint.toVector2(),
await widget.gestureHandler.onScaleUpdate(); details.focalPointDelta.toVector2(),
}, details.horizontalScale,
); details.verticalScale,
details.scale,
details.pointerCount);
},
onScaleEnd: (details) async {
await widget.gestureHandler.onScaleEnd(details.pointerCount);
},
child: widget.child);
} }
} }

View File

@@ -95,7 +95,7 @@ class _ThermionWidgetState extends State<ThermionWidget> {
} }
if (Platform.isWindows) { if (Platform.isWindows) {
return ThermionWidgetWindows(viewer: widget.viewer); return ThermionWidgetWindows(viewer: widget.viewer, view: view!, initial: widget.initial, onResize: widget.onResize);
} }
return ThermionTextureWidget( return ThermionTextureWidget(

View File

@@ -1,14 +1,168 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:thermion_flutter/thermion_flutter.dart'; import 'package:thermion_flutter/src/widgets/src/resize_observer.dart';
import 'package:thermion_flutter/src/widgets/src/transparent_filament_widget.dart';
import 'package:thermion_flutter/thermion_flutter.dart' as t;
import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
class ThermionWidgetWindows extends StatelessWidget { class ThermionWidgetWindows extends StatefulWidget {
final ThermionViewer viewer; final t.ThermionViewer viewer;
final t.View view;
///
///
///
final Widget? initial;
///
/// A callback that will be invoked whenever this widget (and the underlying texture is resized).
///
final Future Function(Size size, t.View view, double pixelRatio)? onResize;
const ThermionWidgetWindows({super.key, required this.viewer, this.initial, this.onResize, required this.view});
@override
State<StatefulWidget> createState() => _ThermionWidgetWindowsState();
}
class _ThermionWidgetWindowsState extends State<ThermionWidgetWindows> {
ThermionFlutterWindow? _window;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
await widget.viewer.initialized;
var dpr = MediaQuery.of(context).devicePixelRatio;
final renderBox = ((context.findRenderObject()) as RenderBox);
var size = renderBox.size;
var width = (size.width * dpr).ceil();
var height = (size.height * dpr).ceil();
final offset = renderBox.localToGlobal(Offset.zero);
final offsetLeft = (offset.dx * dpr).toInt();
final offsetTop = (offset.dy * dpr).toInt();
_window = await t.ThermionFlutterPlatform.instance.createWindow(width, height, offsetLeft, offsetTop);
await widget.view.updateViewport(_window!.width, _window!.height);
try {
await widget.onResize?.call(
Size(_window!.width.toDouble(), _window!.height.toDouble()),
widget.view,
dpr);
} catch (err, st) {
print(err);
print(st);
}
if (mounted) {
setState(() {});
}
_requestFrame();
widget.viewer.onDispose(() async {
var window = _window;
if (mounted) {
setState(() {});
}
await window?.destroy();
});
});
}
bool _rendering = false;
void _requestFrame() {
WidgetsBinding.instance.scheduleFrameCallback((d) async {
if (widget.viewer.rendering && !_rendering) {
_rendering = true;
await widget.viewer.requestFrame();
_rendering = false;
}
_requestFrame();
});
}
final _resizing = <Future>[];
Timer? _resizeTimer;
Future _resize(Size oldSize, Size newSize) async {
await Future.wait(_resizing);
_resizeTimer?.cancel();
_resizeTimer = Timer(const Duration(milliseconds: 100), () async {
await Future.wait(_resizing);
if (!mounted) {
return;
}
if (newSize.width == _window?.width &&
newSize.height == _window?.height) {
return;
}
final completer = Completer();
_resizing.add(completer.future);
final dpr = MediaQuery.of(context).devicePixelRatio;
newSize *= dpr;
var newWidth = newSize.width.ceil();
var newHeight = newSize.height.ceil();
final renderBox = context.findRenderObject() as RenderBox;
final offset = renderBox.localToGlobal(Offset.zero);
final offsetLeft = (offset.dx * dpr).toInt();
final offsetTop = (offset.dy * dpr).toInt();
await _window?.resize(
newWidth,
newHeight,
offsetLeft,
offsetTop,
);
await widget.view.updateViewport(_window!.width, _window!.height);
await widget.onResize?.call(
Size(_window!.width.toDouble(), _window!.height.toDouble()),
widget.view,
dpr);
if (!mounted) {
return;
}
setState(() {});
completer.complete();
_resizing.remove(completer.future);
});
}
const ThermionWidgetWindows({super.key, required this.viewer});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
// TODO: implement build if (_window == null) {
throw UnimplementedError(); return widget.initial ?? Container(color: Colors.red);
}
return ResizeObserver(
onResized: _resize,
child: CustomPaint(painter:TransparencyPainter()));
} }
} }

View File

@@ -1,6 +1,6 @@
name: thermion_flutter name: thermion_flutter
description: Flutter plugin for 3D rendering with the Thermion toolkit. description: Flutter plugin for 3D rendering with the Thermion toolkit.
version: 0.2.1-dev.4 version: 0.2.1-dev.7
homepage: https://thermion.dev homepage: https://thermion.dev
repository: https://github.com/nmfisher/thermion repository: https://github.com/nmfisher/thermion
@@ -17,13 +17,19 @@ dependencies:
plugin_platform_interface: ^2.0.0 plugin_platform_interface: ^2.0.0
ffi: ^2.1.2 ffi: ^2.1.2
animation_tools_dart: ^0.1.0 animation_tools_dart: ^0.1.0
thermion_dart: ^0.2.1-dev.0.0.5 thermion_dart: ^0.2.1-dev.0.0.8
thermion_flutter_platform_interface: ^0.2.1-dev.4 thermion_flutter_platform_interface: ^0.2.1-dev.7
thermion_flutter_ffi: ^0.2.1-dev.4 thermion_flutter_ffi: ^0.2.1-dev.7
thermion_flutter_web: ^0.1.0+6 thermion_flutter_web: ^0.1.0+9
logging: ^1.2.0 logging: ^1.2.0
web: ^1.0.0 web: ^1.0.0
dependency_overrides:
thermion_dart:
path: ../../thermion_dart
thermion_flutter_platform_interface:
path: ../thermion_flutter_platform_interface
thermion_flutter_ffi:
path: ../thermion_flutter_ffi
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter

View File

@@ -152,8 +152,20 @@ LRESULT CALLBACK FilamentWindowProc(HWND const window, UINT const message,
break; break;
} }
case WM_ERASEBKGND: { case WM_ERASEBKGND: {
// Prevent erasing of |window| when it is unfocused and minimized or HDC hdc = (HDC)wparam;
// moved out of screen etc. RECT rect;
GetClientRect(window, &rect);
// Get the BackingWindow instance associated with this window
BackingWindow* backing_window = reinterpret_cast<BackingWindow*>(
GetWindowLongPtr(window, GWLP_USERDATA));
if (backing_window) {
HBRUSH brush = CreateSolidBrush(RGB(0, 255, 0));
FillRect(hdc, &rect, brush);
DeleteObject(brush);
}
break; break;
} }
case WM_SIZE: case WM_SIZE:
@@ -346,8 +358,6 @@ void BackingWindow::Resize(int width, int height, int left, int top) {
_top = top; _top = top;
RECT flutterViewRect; RECT flutterViewRect;
::GetWindowRect(_flutterViewWindow, &flutterViewRect); ::GetWindowRect(_flutterViewWindow, &flutterViewRect);
std::cout << "Resizing to " << _width << " x " << _height << " with LT" << _left << " " << _top << " flutter view rect" << flutterViewRect.left << " " << flutterViewRect.top << " " << flutterViewRect.right << " " << flutterViewRect.bottom << std::endl;
::SetWindowPos(_windowHandle, _flutterRootWindow, flutterViewRect.left + _left, ::SetWindowPos(_windowHandle, _flutterRootWindow, flutterViewRect.left + _left,
flutterViewRect.top + _top, _width, _height, flutterViewRect.top + _top, _width, _height,
SWP_NOACTIVATE); SWP_NOACTIVATE);

View File

@@ -172,8 +172,6 @@ void ThermionFlutterPlugin::CreateTexture(
auto height = (uint32_t)round(dHeight ); auto height = (uint32_t)round(dHeight );
auto left = (uint32_t)round(dLeft ); auto left = (uint32_t)round(dLeft );
auto top = (uint32_t)round(dTop ); auto top = (uint32_t)round(dTop );
std::cout << "Using " << width << "x" << height << std::endl;
// create a single shared context for the life of the application // create a single shared context for the life of the application
// this will be used to create a backing texture and passed to Filament // this will be used to create a backing texture and passed to Filament
@@ -182,8 +180,10 @@ void ThermionFlutterPlugin::CreateTexture(
_context = std::make_unique<FlutterEGLContext>(_pluginRegistrar, _textureRegistrar); _context = std::make_unique<FlutterEGLContext>(_pluginRegistrar, _textureRegistrar);
#else #else
_context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar); _context = std::make_unique<WGLContext>(_pluginRegistrar, _textureRegistrar);
std::cout << "Created WGL context" << std::endl;
#endif #endif
} }
_context->CreateRenderingSurface(width, height, std::move(result), left, top); _context->CreateRenderingSurface(width, height, std::move(result), left, top);
} }
@@ -210,7 +210,7 @@ void ThermionFlutterPlugin::DestroyTexture(
void ThermionFlutterPlugin::HandleMethodCall( void ThermionFlutterPlugin::HandleMethodCall(
const flutter::MethodCall<flutter::EncodableValue> &methodCall, const flutter::MethodCall<flutter::EncodableValue> &methodCall,
std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) { std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
// std::cout << methodCall.method_name().c_str() << std::endl;
if (methodCall.method_name() == "usesBackingWindow") { if (methodCall.method_name() == "usesBackingWindow") {
result->Success(flutter::EncodableValue( result->Success(flutter::EncodableValue(
#ifdef WGL_USE_BACKING_WINDOW #ifdef WGL_USE_BACKING_WINDOW
@@ -239,18 +239,19 @@ void ThermionFlutterPlugin::HandleMethodCall(
int dHeight = *(std::get_if<int>(&(args->at(1)))); int dHeight = *(std::get_if<int>(&(args->at(1))));
int dLeft = *(std::get_if<int>(&(args->at(2)))); int dLeft = *(std::get_if<int>(&(args->at(2))));
int dTop = *(std::get_if<int>(&(args->at(3)))); int dTop = *(std::get_if<int>(&(args->at(3))));
auto width = (uint32_t)round(dWidth ); auto width = static_cast<uint32_t>(dWidth);
auto height = (uint32_t)round(dHeight ); auto height = static_cast<uint32_t>(dHeight);
auto left = (uint32_t)round(dLeft ); auto left = static_cast<uint32_t>(dLeft);
auto top = (uint32_t)round(dTop ); auto top = static_cast<uint32_t>(dTop );
_context->ResizeRenderingSurface(width, height, left, top); _context->ResizeRenderingSurface(width, height, left, top);
result->Success(); result->Success();
#else #else
result->Error("ERROR", "resizeWindow is only available when using a backing window"); result->Error("ERROR", "resizeWindow is only available when using a backing window");
#endif #endif
} else if (methodCall.method_name() == "createTexture") { } else if (methodCall.method_name() == "createWindow") {
CreateTexture(methodCall, std::move(result)); CreateTexture(methodCall, std::move(result));
} else if (methodCall.method_name() == "destroyTexture") { } else if (methodCall.method_name() == "destroyWindow") {
DestroyTexture(methodCall, std::move(result)); DestroyTexture(methodCall, std::move(result));
} else if (methodCall.method_name() == "getRenderCallback") { } else if (methodCall.method_name() == "getRenderCallback") {
flutter::EncodableList resultList; flutter::EncodableList resultList;

View File

@@ -45,7 +45,7 @@ WGLContext::WGLContext(flutter::PluginRegistrarWindows *pluginRegistrar,
0, 0,
0, 0,
0, 0,
16, // Number of bits for the depthbuffer 24, // Number of bits for the depthbuffer
0, // Number of bits for the stencilbuffer 0, // Number of bits for the stencilbuffer
0, // Number of Aux buffers in the framebuffer. 0, // Number of Aux buffers in the framebuffer.
PFD_MAIN_PLANE, PFD_MAIN_PLANE,
@@ -117,6 +117,8 @@ void WGLContext::CreateRenderingSurface(
} else { } else {
ResizeRenderingSurface(width, height, left, top); ResizeRenderingSurface(width, height, left, top);
} }
// std::cout << "created window size " << width << "x" << height << " at " << left << "," << top << " with backing handle" << _backingWindow->GetHandle() << std::endl;
std::vector<flutter::EncodableValue> resultList; std::vector<flutter::EncodableValue> resultList;
resultList.push_back(flutter::EncodableValue()); // return null for Flutter texture ID resultList.push_back(flutter::EncodableValue()); // return null for Flutter texture ID
resultList.push_back(flutter::EncodableValue()); // return null for hardware texture ID resultList.push_back(flutter::EncodableValue()); // return null for hardware texture ID

View File

@@ -1,3 +1,15 @@
## 0.2.1-dev.7
- Update a dependency to the latest release.
## 0.2.1-dev.6
- Update a dependency to the latest release.
## 0.2.1-dev.5
- Update a dependency to the latest release.
## 0.2.1-dev.4 ## 0.2.1-dev.4
- Update a dependency to the latest release. - Update a dependency to the latest release.

View File

@@ -7,16 +7,19 @@ import 'package:thermion_flutter_ffi/thermion_flutter_method_channel_interface.d
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
import 'platform_texture.dart'; import 'platform_texture.dart';
/// ///
/// An implementation of [ThermionFlutterPlatform] that uses /// An implementation of [ThermionFlutterPlatform] that uses
/// Flutter platform channels to create a rendering context, /// Flutter platform channels to create a rendering context,
/// resource loaders, and surface/render target(s). /// resource loaders, and a texture that will be used as a render target
/// for a headless swapchain.
/// ///
class ThermionFlutterTextureBackedPlatform class ThermionFlutterTextureBackedPlatform
extends ThermionFlutterMethodChannelInterface { extends ThermionFlutterMethodChannelInterface {
final _logger = Logger("ThermionFlutterTextureBackedPlatform"); final _logger = Logger("ThermionFlutterTextureBackedPlatform");
static SwapChain? _swapChain; static SwapChain? _swapChain;
@@ -52,11 +55,10 @@ class ThermionFlutterTextureBackedPlatform
await texture.resize(width, height, 0, 0); await texture.resize(width, height, 0, 0);
return texture; return texture;
} }
// On MacOS, we currently use textures/render targets, so there's no window to resize
@override @override
Future<ThermionFlutterTexture?> resizeWindow( Future<ThermionFlutterWindow> createWindow(int width, int height, int offsetLeft, int offsetTop) {
int width, int height, int offsetTop, int offsetRight) { // TODO: implement createWindow
throw UnimplementedError(); throw UnimplementedError();
} }
} }

View File

@@ -1,34 +1,45 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'dart:ffi';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart'; import 'package:thermion_dart/src/viewer/src/ffi/thermion_viewer_ffi.dart';
import 'package:thermion_flutter_ffi/thermion_flutter_method_channel_interface.dart'; import 'package:thermion_flutter_ffi/thermion_flutter_method_channel_interface.dart';
import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_platform_interface.dart';
import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart'; import 'package:thermion_flutter_platform_interface/thermion_flutter_texture.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:thermion_flutter_platform_interface/thermion_flutter_window.dart';
/// ///
/// An implementation of [ThermionFlutterPlatform] that uses /// A Windows-only implementation of [ThermionFlutterPlatform] that uses
/// Flutter platform channels to create a rendering context, /// a Flutter platform channel to create a rendering context,
/// resource loaders, and surface/render target(s). /// resource loader and a native HWND that will be sit behind the running
/// Flutter application.
/// ///
class ThermionFlutterWindows class ThermionFlutterWindows
extends ThermionFlutterMethodChannelInterface { extends ThermionFlutterMethodChannelInterface {
final _channel = const MethodChannel("dev.thermion.flutter/event"); final _channel = const MethodChannel("dev.thermion.flutter/event");
final _logger = Logger("ThermionFlutterWindows"); final _logger = Logger("ThermionFlutterWindows");
ThermionViewerFFI? _viewer; ThermionViewer? _viewer;
ThermionFlutterWindows._() {}
SwapChain? _swapChain; SwapChain? _swapChain;
ThermionFlutterWindows._() {}
static void registerWith() { static void registerWith() {
ThermionFlutterPlatform.instance = ThermionFlutterWindows._(); ThermionFlutterPlatform.instance = ThermionFlutterWindows._();
} }
@override
Future<ThermionViewer> createViewer({ThermionFlutterOptions? options}) async {
if(_viewer != null) {
throw Exception("Only one viewer should be instantiated over the life of the app");
}
_viewer = await super.createViewer(options: options);
return _viewer!;
}
/// ///
/// Not supported on Windows. Throws an exception. /// Not supported on Windows. Throws an exception.
/// ///
@@ -37,64 +48,85 @@ class ThermionFlutterWindows
throw UnimplementedError(); throw UnimplementedError();
} }
bool _resizing = false;
@override
Future<ThermionFlutterWindow> createWindow(int width, int height, int offsetLeft, int offsetTop) async {
var result = await _channel
.invokeMethod("createWindow", [width, height, offsetLeft, offsetLeft]);
if (result == null || result[2] == -1) {
throw Exception("Failed to create window");
}
var window =
ThermionFlutterWindowImpl(result[2], _channel, viewer!);
await window.resize(width, height, offsetLeft, offsetTop);
var view = await _viewer!.getViewAt(0);
await view.updateViewport(width, height);
_swapChain = await _viewer!.createSwapChain(window.handle);
await view.setRenderable(true, _swapChain!);
return window;
}
}
class ThermionFlutterWindowImpl extends ThermionFlutterWindow {
final ThermionViewer viewer;
final int handle;
int height = 0;
int width = 0;
int offsetLeft = 0;
int offsetTop = 0;
final MethodChannel _channel;
ThermionFlutterWindowImpl(this.handle, this._channel, this.viewer);
@override
Future destroy() async {
await _channel
.invokeMethod("destroyWindow", this.handle);
}
@override
Future markFrameAvailable() {
// TODO: implement markFrameAvailable
throw UnimplementedError();
}
bool _resizing = false;
/// ///
/// Called by [ThermionWidget] to resize a texture. Don't call this yourself. /// Called by [ThermionWidget] to resize the window. Don't call this yourself.
/// ///
@override @override
Future resizeWindow( Future resize(
int width, int height, int offsetLeft, int offsetTop) async { int width, int height, int offsetLeft, int offsetTop) async {
if (_resizing) { if (_resizing) {
throw Exception("Resize underway"); throw Exception("Resize underway");
} }
throw Exception("TODO"); if (width == this.width && height == this.height && this.offsetLeft == offsetLeft && this.offsetTop == offsetTop) {
return;
}
// final view = await this._viewer!.getViewAt(0); this.width = width;
// final viewport = await view.getViewport(); this.height = height;
// final swapChain = await this._viewer.getSwapChainAt(0); this.offsetLeft = offsetLeft;
this.offsetTop = offsetTop;
// if (width == viewport.width && height - viewport.height == 0) { _resizing = true;
// return;
// }
// _resizing = true; await _channel
// bool wasRendering = _viewer!.rendering; .invokeMethod("resizeWindow", [width, height, offsetLeft, offsetTop]);
// await _viewer!.setRendering(false); _resizing = false;
// await _swapChain?.destroy();
// var result = await _channel
// .invokeMethod("createTexture", [width, height, offsetLeft, offsetLeft]);
// if (result == null || result[0] == -1) {
// throw Exception("Failed to create texture");
// }
// var newTexture =
// ThermionFlutterTexture(result[0], result[1], width, height, result[2]);
// await _viewer!.createSwapChain(width, height,
// surface: newTexture.surfaceAddress == null
// ? nullptr
// : Pointer<Void>.fromAddress(newTexture.surfaceAddress!));
// if (newTexture.hardwareTextureId != null) {
// // ignore: unused_local_variable
// var renderTarget = await _viewer!
// .createRenderTarget(width, height, newTexture.hardwareTextureId!);
// }
// await _viewer!
// .updateViewportAndCameraProjection(width.toDouble(), height.toDouble());
// if (wasRendering) {
// await _viewer!.setRendering(true);
// }
// _textures.add(newTexture);
// _resizing = false;
// return newTexture;
} }
}
}

View File

@@ -1,7 +1,7 @@
name: thermion_flutter_ffi name: thermion_flutter_ffi
description: An FFI interface for the thermion_flutter plugin (all platforms except web). description: An FFI interface for the thermion_flutter plugin (all platforms except web).
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
version: 0.2.1-dev.4 version: 0.2.1-dev.7
environment: environment:
sdk: ">=3.3.0 <4.0.0" sdk: ">=3.3.0 <4.0.0"
@@ -22,11 +22,17 @@ dependencies:
flutter: flutter:
sdk: flutter sdk: flutter
plugin_platform_interface: ^2.1.0 plugin_platform_interface: ^2.1.0
thermion_flutter_platform_interface: ^0.2.1-dev.4 thermion_flutter_platform_interface: ^0.2.1-dev.7
thermion_dart: ^0.2.1-dev.0.0.5 thermion_dart: ^0.2.1-dev.0.0.8
logging: ^1.2.0 logging: ^1.2.0
dependency_overrides:
thermion_dart:
path: ../../thermion_dart
thermion_flutter_platform_interface:
path: ../thermion_flutter_platform_interface
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
mockito: ^5.0.0 mockito: ^5.0.0

View File

@@ -1,3 +1,15 @@
## 0.2.1-dev.7
- Update a dependency to the latest release.
## 0.2.1-dev.6
- Update a dependency to the latest release.
## 0.2.1-dev.5
- Update a dependency to the latest release.
## 0.2.1-dev.4 ## 0.2.1-dev.4
- Update a dependency to the latest release. - Update a dependency to the latest release.

View File

@@ -4,6 +4,7 @@ import 'package:thermion_dart/thermion_dart.dart' as t;
import 'package:plugin_platform_interface/plugin_platform_interface.dart'; import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'package:thermion_dart/thermion_dart.dart'; import 'package:thermion_dart/thermion_dart.dart';
import 'thermion_flutter_texture.dart'; import 'thermion_flutter_texture.dart';
import 'thermion_flutter_window.dart';
class ThermionFlutterOptions { class ThermionFlutterOptions {
final String? uberarchivePath; final String? uberarchivePath;
@@ -41,7 +42,13 @@ abstract class ThermionFlutterPlatform extends PlatformInterface {
t.View view, int width, int height); t.View view, int width, int height);
/// ///
/// Create a rendering window.
/// ///
/// This is internal; unless you are [thermion_*] package developer, don't
/// call this yourself. May not be supported on all platforms.
/// ///
Future resizeWindow(int width, int height, int offsetTop, int offsetRight); Future<ThermionFlutterWindow> createWindow(
int width, int height, int offsetLeft, int offsetTop);
} }

View File

@@ -0,0 +1,16 @@
abstract class ThermionFlutterWindow {
int get width;
int get height;
int get handle;
///
/// Destroy a texture and clean up the texture cache (if applicable).
///
Future destroy();
Future resize(int width, int height, int left, int top);
Future markFrameAvailable();
}

View File

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

View File

@@ -1,3 +1,15 @@
## 0.1.0+9
- Update a dependency to the latest release.
## 0.1.0+8
- Update a dependency to the latest release.
## 0.1.0+7
- Update a dependency to the latest release.
## 0.1.0+6 ## 0.1.0+6
- Update a dependency to the latest release. - Update a dependency to the latest release.

View File

@@ -1,7 +1,7 @@
name: thermion_flutter_web name: thermion_flutter_web
description: A web platform interface for the thermion_flutter plugin. description: A web platform interface for the thermion_flutter plugin.
repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter repository: https://github.com/nmfisher/thermion_flutter/thermion_flutter
version: 0.1.0+6 version: 0.1.0+9
environment: environment:
sdk: ">=3.3.0 <4.0.0" sdk: ">=3.3.0 <4.0.0"
@@ -20,8 +20,8 @@ dependencies:
sdk: flutter sdk: flutter
plugin_platform_interface: ^2.1.0 plugin_platform_interface: ^2.1.0
web: ^1.0.0 web: ^1.0.0
thermion_dart: ^0.2.1-dev.0.0.5 thermion_dart: ^0.2.1-dev.0.0.8
thermion_flutter_platform_interface: ^0.2.1-dev.4 thermion_flutter_platform_interface: ^0.2.1-dev.7
flutter_web_plugins: flutter_web_plugins:
sdk: flutter sdk: flutter