refactoring
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../../../../utils/src/matrix.dart';
|
||||
@@ -8,11 +10,10 @@ import 'thermion_dart.g.dart' as g;
|
||||
|
||||
class FFICamera extends Camera {
|
||||
final Pointer<g.TCamera> camera;
|
||||
final Pointer<g.TEngine> engine;
|
||||
final Pointer<g.TTransformManager> transformManager;
|
||||
final FFIFilamentApp app;
|
||||
late ThermionEntity _entity;
|
||||
|
||||
FFICamera(this.camera, this.engine, this.transformManager) {
|
||||
FFICamera(this.camera, this.app) {
|
||||
_entity = g.Camera_getEntity(camera);
|
||||
}
|
||||
|
||||
@@ -30,7 +31,8 @@ class FFICamera extends Camera {
|
||||
@override
|
||||
Future setTransform(Matrix4 transform) async {
|
||||
var entity = g.Camera_getEntity(camera);
|
||||
g.TransformManager_setTransform(transformManager, entity, matrix4ToDouble4x4(transform));
|
||||
g.TransformManager_setTransform(
|
||||
app.transformManager, entity, matrix4ToDouble4x4(transform));
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -84,9 +86,8 @@ class FFICamera extends Camera {
|
||||
|
||||
@override
|
||||
Future setProjection(Projection projection, double left, double right,
|
||||
double bottom, double top, double near, double far) async {
|
||||
double bottom, double top, double near, double far) async {
|
||||
var pType = g.Projection.values[projection.index];
|
||||
g.Camera_setProjection(camera, pType, left,
|
||||
right, bottom, top, near, far);
|
||||
g.Camera_setProjection(camera, pType, left, right, bottom, top, near, far);
|
||||
}
|
||||
}
|
||||
|
||||
150
thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart
Normal file
150
thermion_dart/lib/src/viewer/src/ffi/src/ffi_filament_app.dart
Normal file
@@ -0,0 +1,150 @@
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/filament/filament.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
|
||||
|
||||
class FFIFilamentConfig extends FilamentConfig<RenderCallback, Pointer<Void>> {
|
||||
FFIFilamentConfig(
|
||||
{required super.backend,
|
||||
required super.resourceLoader,
|
||||
required super.uberArchivePath});
|
||||
}
|
||||
|
||||
class FFIFilamentApp extends FilamentApp<Pointer> {
|
||||
static FFIFilamentApp? _instance;
|
||||
|
||||
final Pointer<TEngine> engine;
|
||||
final Pointer<TGltfAssetLoader> gltfAssetLoader;
|
||||
final Pointer<TGltfResourceLoader> gltfResourceLoader;
|
||||
final Pointer<TRenderer> renderer;
|
||||
final Pointer<TTransformManager> transformManager;
|
||||
final Pointer<TLightManager> lightManager;
|
||||
final Pointer<TRenderableManager> renderableManager;
|
||||
final Pointer<TMaterialProvider> ubershaderMaterialProvider;
|
||||
final Pointer<TRenderTicker> renderTicker;
|
||||
|
||||
FFIFilamentApp(
|
||||
this.engine,
|
||||
this.gltfAssetLoader,
|
||||
this.gltfResourceLoader,
|
||||
this.renderer,
|
||||
this.transformManager,
|
||||
this.lightManager,
|
||||
this.renderableManager,
|
||||
this.ubershaderMaterialProvider,
|
||||
this.renderTicker)
|
||||
: super(
|
||||
engine: engine,
|
||||
gltfAssetLoader: gltfAssetLoader,
|
||||
gltfResourceLoader: gltfResourceLoader,
|
||||
renderer: renderer,
|
||||
transformManager: transformManager,
|
||||
lightManager: lightManager,
|
||||
renderableManager: renderableManager,
|
||||
ubershaderMaterialProvider: ubershaderMaterialProvider);
|
||||
|
||||
Future<FFIFilamentApp> create(FFIFilamentConfig config) async {
|
||||
if (_instance == null) {
|
||||
RenderLoop_destroy();
|
||||
RenderLoop_create();
|
||||
|
||||
final engine = await withPointerCallback<TEngine>((cb) =>
|
||||
Engine_createRenderThread(
|
||||
TBackend.values[config.backend.index].index,
|
||||
config.platform ?? nullptr,
|
||||
config.sharedContext ?? nullptr,
|
||||
config.stereoscopicEyeCount,
|
||||
config.disableHandleUseAfterFreeCheck,
|
||||
cb));
|
||||
|
||||
final gltfResourceLoader = await withPointerCallback<TGltfResourceLoader>(
|
||||
(cb) => GltfResourceLoader_createRenderThread(engine, cb));
|
||||
final gltfAssetLoader = await withPointerCallback<TGltfAssetLoader>(
|
||||
(cb) => GltfAssetLoader_createRenderThread(engine, nullptr, cb));
|
||||
final renderer = await withPointerCallback<TRenderer>(
|
||||
(cb) => Engine_createRendererRenderThread(engine, cb));
|
||||
final ubershaderMaterialProvider =
|
||||
await withPointerCallback<TMaterialProvider>(
|
||||
(cb) => GltfAssetLoader_getMaterialProvider(gltfAssetLoader));
|
||||
|
||||
final transformManager = Engine_getTransformManager(engine);
|
||||
final lightManager = Engine_getLightManager(engine);
|
||||
final renderableManager = Engine_getRenderableManager(engine);
|
||||
|
||||
final renderTicker = await withPointerCallback<TRenderTicker>(
|
||||
(cb) => RenderTicker_create());
|
||||
|
||||
_instance = FFIFilamentApp(
|
||||
engine,
|
||||
gltfAssetLoader,
|
||||
gltfResourceLoader,
|
||||
renderer,
|
||||
transformManager,
|
||||
lightManager,
|
||||
renderableManager,
|
||||
ubershaderMaterialProvider);
|
||||
}
|
||||
return _instance!;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height,
|
||||
{bool hasStencilBuffer = false}) async {
|
||||
var flags = TSWAP_CHAIN_CONFIG_TRANSPARENT | TSWAP_CHAIN_CONFIG_READABLE;
|
||||
if (hasStencilBuffer) {
|
||||
flags |= TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER;
|
||||
}
|
||||
final swapChain = await withPointerCallback<TSwapChain>((cb) =>
|
||||
Engine_createHeadlessSwapChainRenderThread(
|
||||
this.engine, width, height, flags, cb));
|
||||
return FFISwapChain(swapChain);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<SwapChain> createSwapChain(Pointer window,
|
||||
{bool hasStencilBuffer = false}) async {
|
||||
var flags = TSWAP_CHAIN_CONFIG_TRANSPARENT | TSWAP_CHAIN_CONFIG_READABLE;
|
||||
if (hasStencilBuffer) {
|
||||
flags |= TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER;
|
||||
}
|
||||
final swapChain = await withPointerCallback<TSwapChain>((cb) =>
|
||||
Engine_createSwapChainRenderThread(
|
||||
this.engine, window.cast<Void>(), flags, cb));
|
||||
return FFISwapChain(swapChain);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroySwapChain(SwapChain swapChain) async {
|
||||
await withVoidCallback((callback) {
|
||||
Engine_destroySwapChainRenderThread(
|
||||
engine, (swapChain as FFISwapChain).swapChain, callback);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroy() {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(int width, int height,
|
||||
{covariant FFITexture? color, covariant FFITexture? depth}) async {
|
||||
final renderTarget = await withPointerCallback<TRenderTarget>((cb) {
|
||||
RenderTarget_createRenderThread(engine, width, height,
|
||||
color?.pointer ?? nullptr, depth?.pointer ?? nullptr, cb);
|
||||
});
|
||||
|
||||
return FFIRenderTarget(renderTarget, this);
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,30 @@
|
||||
import 'dart:ffi';
|
||||
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/callbacks.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
class FFIRenderTarget extends RenderTarget {
|
||||
final Pointer<TRenderTarget> renderTarget;
|
||||
final Pointer<TViewer> viewer;
|
||||
final Pointer<TEngine> engine;
|
||||
final FFIFilamentApp app;
|
||||
|
||||
FFIRenderTarget(this.renderTarget, this.viewer, this.engine);
|
||||
FFIRenderTarget(this.renderTarget, this.app);
|
||||
|
||||
@override
|
||||
Future<Texture> getColorTexture() async {
|
||||
final ptr = RenderTarget_getColorTexture(renderTarget);
|
||||
return FFITexture(engine, ptr);
|
||||
return FFITexture(app.engine, ptr);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Texture> getDepthTexture() async {
|
||||
final ptr = RenderTarget_getDepthTexture(renderTarget);
|
||||
return FFITexture(engine, ptr);
|
||||
return FFITexture(app.engine, ptr);
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroy() async {
|
||||
await withVoidCallback((cb) => RenderTarget_destroy(app.engine, renderTarget));
|
||||
}
|
||||
}
|
||||
|
||||
19
thermion_dart/lib/src/viewer/src/ffi/src/ffi_scene.dart
Normal file
19
thermion_dart/lib/src/viewer/src/ffi/src/ffi_scene.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart';
|
||||
import 'callbacks.dart';
|
||||
import 'ffi_camera.dart';
|
||||
|
||||
class FFIScene extends Scene {
|
||||
final Pointer<TScene> scene;
|
||||
final FFIFilamentApp app;
|
||||
|
||||
FFIRenderTarget? renderTarget;
|
||||
|
||||
FFIScene(this.scene, this.app) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@ import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
class FFISwapChain extends SwapChain {
|
||||
final Pointer<TSwapChain> swapChain;
|
||||
final Pointer<TViewer> viewer;
|
||||
|
||||
FFISwapChain(this.swapChain, this.viewer);
|
||||
FFISwapChain(this.swapChain);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,22 @@
|
||||
import 'dart:ffi';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart';
|
||||
import 'callbacks.dart';
|
||||
import 'ffi_camera.dart';
|
||||
import 'thermion_viewer_ffi.dart';
|
||||
|
||||
class FFIView extends View {
|
||||
final Pointer<TView> view;
|
||||
final Pointer<TViewer> viewer;
|
||||
final Pointer<TEngine> engine;
|
||||
final FFIFilamentApp app;
|
||||
|
||||
FFIRenderTarget? renderTarget;
|
||||
|
||||
FFIView(this.view, this.viewer, this.engine) {
|
||||
FFIView(this.view, this.app) {
|
||||
final renderTargetPtr = View_getRenderTarget(view);
|
||||
if (renderTargetPtr != nullptr) {
|
||||
renderTarget = FFIRenderTarget(
|
||||
renderTargetPtr,
|
||||
viewer,
|
||||
engine
|
||||
);
|
||||
renderTarget = FFIRenderTarget(renderTargetPtr, app);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,10 +52,9 @@ class FFIView extends View {
|
||||
|
||||
@override
|
||||
Future<Camera> getCamera() async {
|
||||
final engine = Viewer_getEngine(viewer);
|
||||
final transformManager = Engine_getTransformManager(engine);
|
||||
final transformManager = Engine_getTransformManager(app.engine);
|
||||
final cameraPtr = View_getCamera(view);
|
||||
return FFICamera(cameraPtr, engine, transformManager);
|
||||
return FFICamera(cameraPtr, app.engine, transformManager);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -73,7 +68,7 @@ class FFIView extends View {
|
||||
}
|
||||
|
||||
Future setRenderable(bool renderable, FFISwapChain swapChain) async {
|
||||
Viewer_setViewRenderable(viewer, swapChain.swapChain, view, renderable);
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -90,8 +85,7 @@ class FFIView extends View {
|
||||
|
||||
@override
|
||||
Future setToneMapper(ToneMapper mapper) async {
|
||||
final engine = await Viewer_getEngine(viewer);
|
||||
View_setToneMappingRenderThread(view, engine, mapper.index);
|
||||
View_setToneMappingRenderThread(view, app.engine, mapper.index);
|
||||
}
|
||||
|
||||
Future setStencilBufferEnabled(bool enabled) async {
|
||||
@@ -114,4 +108,8 @@ class FFIView extends View {
|
||||
Future setRenderQuality(QualityLevel quality) async {
|
||||
View_setRenderQuality(view, TQualityLevel.values[quality.index]);
|
||||
}
|
||||
|
||||
Future setScene(covariant FFIScene scene) async {
|
||||
await withVoidCallback((cb) => View_setScene(view, scene.scene));
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,11 +4,16 @@ import 'dart:math';
|
||||
import 'dart:typed_data';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_asset.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_filament_app.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_gizmo.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_material.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_render_target.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_scene.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_swapchain.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/ffi/src/ffi_texture.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/filament/filament.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/config.dart';
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
import 'package:vector_math/vector_math_64.dart' as v64;
|
||||
import '../../../../utils/src/matrix.dart';
|
||||
@@ -19,84 +24,24 @@ import 'callbacks.dart';
|
||||
import 'ffi_camera.dart';
|
||||
import 'ffi_view.dart';
|
||||
|
||||
class FFIBindings {
|
||||
final Pointer<TSceneManager> sceneManager;
|
||||
final Pointer<TEngine> engine;
|
||||
final Pointer<TMaterialProvider> unlitMaterialProvider;
|
||||
final Pointer<TMaterialProvider> ubershaderMaterialProvider;
|
||||
final Pointer<TTransformManager> transformManager;
|
||||
final Pointer<TLightManager> lightManager;
|
||||
final Pointer<TRenderableManager> renderableManager;
|
||||
final Pointer<TViewer> viewer;
|
||||
final Pointer<TAnimationManager> animationManager;
|
||||
final Pointer<TNameComponentManager> nameComponentManager;
|
||||
final Pointer<TRenderer> renderer;
|
||||
|
||||
FFIBindings(
|
||||
{required this.renderer,
|
||||
required this.sceneManager,
|
||||
required this.engine,
|
||||
required this.unlitMaterialProvider,
|
||||
required this.ubershaderMaterialProvider,
|
||||
required this.transformManager,
|
||||
required this.lightManager,
|
||||
required this.renderableManager,
|
||||
required this.viewer,
|
||||
required this.animationManager,
|
||||
required this.nameComponentManager});
|
||||
}
|
||||
|
||||
// ignore: constant_identifier_names
|
||||
const ThermionEntity FILAMENT_ASSET_ERROR = 0;
|
||||
|
||||
typedef RenderCallback = Pointer<NativeFunction<Void Function(Pointer<Void>)>>;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
class ThermionViewerFFI extends ThermionViewer {
|
||||
final _logger = Logger("ThermionViewerFFI");
|
||||
|
||||
Pointer<TSceneManager>? _sceneManager;
|
||||
Pointer<TEngine>? _engine;
|
||||
Pointer<TMaterialProvider>? _unlitMaterialProvider;
|
||||
Pointer<TMaterialProvider>? _ubershaderMaterialProvider;
|
||||
Pointer<TTransformManager>? _transformManager;
|
||||
Pointer<TLightManager>? _lightManager;
|
||||
Pointer<TRenderableManager>? _renderableManager;
|
||||
Pointer<TViewer>? _viewer;
|
||||
Pointer<TAnimationManager>? _animationManager;
|
||||
Pointer<TNameComponentManager>? _nameComponentManager;
|
||||
|
||||
late FFIBindings bindings;
|
||||
final String? uberArchivePath;
|
||||
|
||||
final _initialized = Completer<bool>();
|
||||
Future<bool> get initialized => _initialized.future;
|
||||
|
||||
final Pointer<Void> resourceLoader;
|
||||
|
||||
var _driver = nullptr.cast<Void>();
|
||||
|
||||
late final RenderCallback _renderCallback;
|
||||
var _renderCallbackOwner = nullptr.cast<Void>();
|
||||
|
||||
var _sharedContext = nullptr.cast<Void>();
|
||||
|
||||
late NativeCallable<PickCallbackFunction> _onPickResultCallable;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
ThermionViewerFFI(
|
||||
{RenderCallback? renderCallback,
|
||||
Pointer<Void>? renderCallbackOwner,
|
||||
required this.resourceLoader,
|
||||
Pointer<Void>? driver,
|
||||
Pointer<Void>? sharedContext,
|
||||
this.uberArchivePath}) {
|
||||
this._renderCallbackOwner = renderCallbackOwner ?? nullptr;
|
||||
this._renderCallback = renderCallback ?? nullptr;
|
||||
this._driver = driver ?? nullptr;
|
||||
this._sharedContext = sharedContext ?? nullptr;
|
||||
late final FFIFilamentApp app;
|
||||
late final FFIRenderTarget? renderTarget;
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
ThermionViewerFFI(this.app, {this.renderTarget}) {
|
||||
_onPickResultCallable =
|
||||
NativeCallable<PickCallbackFunction>.listener(_onPickResult);
|
||||
|
||||
@@ -107,49 +52,21 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(int width, int height,
|
||||
{int? colorTextureHandle, int? depthTextureHandle}) async {
|
||||
{covariant FFITexture? color, covariant FFITexture? depth}) async {
|
||||
final renderTarget = await withPointerCallback<TRenderTarget>((cb) {
|
||||
Viewer_createRenderTargetRenderThread(_viewer!, colorTextureHandle ?? 0,
|
||||
depthTextureHandle ?? 0, width, height, cb);
|
||||
RenderTarget_createRenderThread(app.engine, width, height,
|
||||
color?.pointer ?? nullptr, depth?.pointer ?? nullptr, cb);
|
||||
});
|
||||
|
||||
return FFIRenderTarget(renderTarget, _viewer!, _engine!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future destroyRenderTarget(FFIRenderTarget renderTarget) async {
|
||||
if (_disposing || _viewer == null) {
|
||||
_logger.info(
|
||||
"Viewer is being (or has been) disposed; this will clean up all render targets.");
|
||||
} else {
|
||||
await withVoidCallback((cb) {
|
||||
Viewer_destroyRenderTargetRenderThread(
|
||||
_viewer!, renderTarget.renderTarget, cb);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<View> createView() async {
|
||||
var view = await withPointerCallback<TView>((cb) {
|
||||
Viewer_createViewRenderThread(_viewer!, cb);
|
||||
});
|
||||
if (view == nullptr) {
|
||||
throw Exception("Failed to create view");
|
||||
}
|
||||
return FFIView(view, _viewer!, _engine!);
|
||||
return FFIRenderTarget(renderTarget, app);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future setViewportAndCameraProjection(double width, double height) async {
|
||||
var mainView = FFIView(Viewer_getViewAt(_viewer!, 0), _viewer!, _engine!);
|
||||
var mainView =
|
||||
FFIView(Viewer_getViewAt(_viewer!, 0), _viewer!, app.engine!);
|
||||
mainView.setViewport(width.toInt(), height.toInt());
|
||||
|
||||
final cameraCount = await getCameraCount();
|
||||
@@ -175,86 +92,25 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height) async {
|
||||
var swapChain = await withPointerCallback<TSwapChain>((callback) {
|
||||
return Viewer_createHeadlessSwapChainRenderThread(
|
||||
_viewer!, width, height, callback);
|
||||
});
|
||||
return FFISwapChain(swapChain, _viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createSwapChain(int surface) async {
|
||||
var swapChain = await withPointerCallback<TSwapChain>((callback) {
|
||||
return Viewer_createSwapChainRenderThread(
|
||||
_viewer!, Pointer<Void>.fromAddress(surface), callback);
|
||||
});
|
||||
return FFISwapChain(swapChain, _viewer!);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroySwapChain(SwapChain swapChain) async {
|
||||
if (_viewer != null) {
|
||||
await withVoidCallback((callback) {
|
||||
Viewer_destroySwapChainRenderThread(
|
||||
_viewer!, (swapChain as FFISwapChain).swapChain, callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
late final FFIView view;
|
||||
late final FFIScene scene;
|
||||
late final FFICamera camera;
|
||||
|
||||
Future _initialize() async {
|
||||
_logger.info("Initializing ThermionViewerFFI");
|
||||
|
||||
Viewer_destroyOnRenderThread(nullptr);
|
||||
|
||||
RenderLoop_destroy();
|
||||
RenderLoop_create();
|
||||
|
||||
final uberarchivePtr =
|
||||
uberArchivePath?.toNativeUtf8(allocator: allocator).cast<Char>() ??
|
||||
nullptr;
|
||||
_viewer = await withPointerCallback(
|
||||
(Pointer<NativeFunction<Void Function(Pointer<TViewer>)>> callback) {
|
||||
Viewer_createOnRenderThread(_sharedContext, _driver, uberarchivePtr,
|
||||
resourceLoader, _renderCallback, _renderCallbackOwner, callback);
|
||||
});
|
||||
|
||||
allocator.free(uberarchivePtr);
|
||||
if (_viewer!.address == 0) {
|
||||
throw Exception("Failed to create viewer. Check logs for details");
|
||||
view = FFIView(
|
||||
await withPointerCallback<TView>(
|
||||
(cb) => Engine_createViewRenderThread(app.engine, cb)),
|
||||
app);
|
||||
scene = FFIScene(Engine_createScene(app.engine), app);
|
||||
await view.setScene(scene);
|
||||
camera = FFICamera(
|
||||
await withPointerCallback<TCamera>(
|
||||
(cb) => Engine_createCameraRenderThread(app.engine, cb)),
|
||||
app);
|
||||
if (renderTarget != null) {
|
||||
await view.setRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
_sceneManager = Viewer_getSceneManager(_viewer!);
|
||||
_unlitMaterialProvider =
|
||||
SceneManager_getUnlitMaterialProvider(_sceneManager!);
|
||||
_ubershaderMaterialProvider =
|
||||
SceneManager_getUbershaderMaterialProvider(_sceneManager!);
|
||||
_engine = Viewer_getEngine(_viewer!);
|
||||
_transformManager = Engine_getTransformManager(_engine!);
|
||||
_lightManager = Engine_getLightManager(_engine!);
|
||||
_animationManager = SceneManager_getAnimationManager(_sceneManager!);
|
||||
_nameComponentManager =
|
||||
SceneManager_getNameComponentManager(_sceneManager!);
|
||||
_renderableManager = Engine_getRenderableManager(_engine!);
|
||||
bindings = FFIBindings(
|
||||
sceneManager: _sceneManager!,
|
||||
engine: _engine!,
|
||||
unlitMaterialProvider: _unlitMaterialProvider!,
|
||||
ubershaderMaterialProvider: _ubershaderMaterialProvider!,
|
||||
transformManager: _transformManager!,
|
||||
lightManager: _lightManager!,
|
||||
renderableManager: _renderableManager!,
|
||||
viewer: _viewer!,
|
||||
animationManager: _animationManager!,
|
||||
nameComponentManager: _nameComponentManager!,
|
||||
renderer: Viewer_getRenderer(_viewer!));
|
||||
this._initialized.complete(true);
|
||||
}
|
||||
|
||||
@@ -272,32 +128,24 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
@override
|
||||
Future setRendering(bool render) async {
|
||||
_rendering = render;
|
||||
// await withVoidCallback((cb) {
|
||||
// set_rendering_render_thread(_viewer!, render, cb);
|
||||
// });
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future render({FFISwapChain? swapChain}) async {
|
||||
final view = (await getViewAt(0)) as FFIView;
|
||||
swapChain ??= FFISwapChain(Viewer_getSwapChainAt(_viewer!, 0), _viewer!);
|
||||
Viewer_renderRenderThread(_viewer!, view.view, swapChain.swapChain);
|
||||
Future render() async {
|
||||
RenderTicker_renderRenderThread(app.renderTicker, 0);
|
||||
// Viewer_renderRenderThread(_viewer!, view.view, swapChain.swapChain);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
@override
|
||||
Future<List<Uint8List>> capture(
|
||||
List<({View view, SwapChain? swapChain, RenderTarget? renderTarget})>
|
||||
targets) async {
|
||||
var renderer = Viewer_getRenderer(_viewer!);
|
||||
|
||||
Future<Uint8List> capture() async {
|
||||
final fence = await withPointerCallback<TFence>((cb) {
|
||||
Engine_createFenceRenderThread(_engine!, cb);
|
||||
Engine_createFenceRenderThread(app.engine!, cb);
|
||||
});
|
||||
|
||||
var pixelBuffers = <Uint8List>[];
|
||||
@@ -337,11 +185,11 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
});
|
||||
|
||||
await withVoidCallback((cb) {
|
||||
Engine_flushAndWaitRenderThead(_engine!, cb);
|
||||
Engine_flushAndWaitRenderThead(app.engine!, cb);
|
||||
});
|
||||
|
||||
await withVoidCallback((cb) {
|
||||
Engine_destroyFenceRenderThread(_engine!, fence, cb);
|
||||
Engine_destroyFenceRenderThread(app.engine!, fence, cb);
|
||||
});
|
||||
|
||||
// await withVoidCallback((cb) {
|
||||
@@ -400,9 +248,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
await mInstance.dispose();
|
||||
}
|
||||
await destroyLights();
|
||||
Viewer_destroyOnRenderThread(_viewer!);
|
||||
|
||||
RenderLoop_destroy();
|
||||
|
||||
_sceneManager = null;
|
||||
_viewer = null;
|
||||
@@ -410,7 +255,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
for (final callback in _onDispose) {
|
||||
await callback.call();
|
||||
}
|
||||
|
||||
await app.destroy();
|
||||
_onDispose.clear();
|
||||
_disposing = false;
|
||||
}
|
||||
@@ -635,7 +480,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
|
||||
var thermionAsset = FFIAsset(
|
||||
asset, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
|
||||
asset, _sceneManager!, app.engine!, _unlitMaterialProvider!, this);
|
||||
|
||||
return thermionAsset;
|
||||
}
|
||||
@@ -675,7 +520,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
throw Exception("An error occurred loading GLB from buffer");
|
||||
}
|
||||
return FFIAsset(
|
||||
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
|
||||
assetPtr, _sceneManager!, app.engine!, _unlitMaterialProvider!, this);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -697,7 +542,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
|
||||
return FFIAsset(
|
||||
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
|
||||
assetPtr, _sceneManager!, app.engine!, _unlitMaterialProvider!, this);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1780,7 +1625,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
|
||||
var asset = FFIAsset(
|
||||
assetPtr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
|
||||
assetPtr, _sceneManager!, app.engine!, _unlitMaterialProvider!, this);
|
||||
|
||||
return asset;
|
||||
}
|
||||
@@ -1841,7 +1686,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
@override
|
||||
Future setPriority(ThermionEntity entityId, int priority) async {
|
||||
RenderableManager_setPriority(_renderableManager!, entityId, priority);
|
||||
RenderableManager_setPriority(app.renderableManager, entityId, priority);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -1899,7 +1744,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
}
|
||||
});
|
||||
_grid = FFIAsset(
|
||||
ptr, _sceneManager!, _engine!, _unlitMaterialProvider!, this);
|
||||
ptr, _sceneManager!, app.engine!, _unlitMaterialProvider!, this);
|
||||
}
|
||||
await _grid!.addToScene();
|
||||
await setLayerVisibility(VisibilityLayers.OVERLAY, true);
|
||||
@@ -1929,7 +1774,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
var bitmask = flags.fold(0, (a, b) => a | b.index);
|
||||
final texturePtr = await withPointerCallback<TTexture>((cb) {
|
||||
Texture_buildRenderThread(
|
||||
_engine!,
|
||||
app.engine!,
|
||||
width,
|
||||
height,
|
||||
depth,
|
||||
@@ -1944,7 +1789,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
throw Exception("Failed to create texture");
|
||||
}
|
||||
return FFITexture(
|
||||
_engine!,
|
||||
app.engine!,
|
||||
texturePtr,
|
||||
);
|
||||
}
|
||||
@@ -1958,7 +1803,6 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
double anisotropy = 0.0,
|
||||
TextureCompareMode compareMode = TextureCompareMode.NONE,
|
||||
TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) async {
|
||||
return FFITextureSampler(TextureSampler_create());
|
||||
final samplerPtr = TextureSampler_create();
|
||||
TextureSampler_setMinFilter(
|
||||
samplerPtr, TSamplerMinFilter.values[minFilter.index]);
|
||||
@@ -2011,9 +1855,10 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
Future<Material> createMaterial(Uint8List data) async {
|
||||
var ptr = await withPointerCallback<TMaterial>((cb) {
|
||||
Engine_buildMaterialRenderThread(_engine!, data.address, data.length, cb);
|
||||
Engine_buildMaterialRenderThread(
|
||||
app.engine!, data.address, data.length, cb);
|
||||
});
|
||||
return FFIMaterial(ptr, _engine!, _sceneManager!);
|
||||
return FFIMaterial(ptr, app.engine!, _sceneManager!);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -2098,7 +1943,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
|
||||
final materialInstance = await withPointerCallback<TMaterialInstance>((cb) {
|
||||
MaterialProvider_createMaterialInstanceRenderThread(
|
||||
_ubershaderMaterialProvider!, key.address, cb);
|
||||
app.ubershaderMaterialProvider, key.address, cb);
|
||||
});
|
||||
if (materialInstance == nullptr) {
|
||||
throw Exception("Failed to create material instance");
|
||||
@@ -2148,7 +1993,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
Future<MaterialInstance> getMaterialInstanceAt(
|
||||
ThermionEntity entity, int index) async {
|
||||
final instancePtr = RenderableManager_getMaterialInstanceAt(
|
||||
_renderableManager!, entity, index);
|
||||
app.renderableManager, entity, index);
|
||||
|
||||
final instance = FFIMaterialInstance(instancePtr, _sceneManager!);
|
||||
return instance;
|
||||
@@ -2254,7 +2099,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
if (view == nullptr) {
|
||||
throw Exception("Failed to get view");
|
||||
}
|
||||
return FFIView(view, _viewer!, _engine!);
|
||||
return FFIView(view, _viewer!, app.engine!);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -2278,7 +2123,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
view,
|
||||
gizmo.cast<TSceneAsset>(),
|
||||
_sceneManager!,
|
||||
_engine!,
|
||||
app.engine!,
|
||||
nullptr,
|
||||
this,
|
||||
gizmoEntities.toSet()
|
||||
@@ -2289,14 +2134,15 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
///
|
||||
Future setCastShadows(ThermionEntity entity, bool castShadows) async {
|
||||
RenderableManager_setCastShadows(_renderableManager!, entity, castShadows);
|
||||
RenderableManager_setCastShadows(
|
||||
app.renderableManager, entity, castShadows);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<bool> isCastShadowsEnabled(ThermionEntity entity) async {
|
||||
return RenderableManager_isShadowCaster(_renderableManager!, entity);
|
||||
return RenderableManager_isShadowCaster(app.renderableManager, entity);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -2304,14 +2150,14 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
Future setReceiveShadows(ThermionEntity entity, bool receiveShadows) async {
|
||||
RenderableManager_setReceiveShadows(
|
||||
_renderableManager!, entity, receiveShadows);
|
||||
app.renderableManager, entity, receiveShadows);
|
||||
}
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<bool> isReceiveShadowsEnabled(ThermionEntity entity) async {
|
||||
return RenderableManager_isShadowReceiver(_renderableManager!, entity);
|
||||
return RenderableManager_isShadowReceiver(app.renderableManager, entity);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -2319,8 +2165,7 @@ class ThermionViewerFFI extends ThermionViewer {
|
||||
///
|
||||
Future setClearOptions(
|
||||
Vector4 clearColor, int clearStencil, bool clear, bool discard) async {
|
||||
final renderer = Viewer_getRenderer(_viewer!);
|
||||
Renderer_setClearOptions(renderer, clearColor.r, clearColor.g, clearColor.b,
|
||||
clearColor.a, clearStencil, clear, discard);
|
||||
Renderer_setClearOptions(app.renderer, clearColor.r, clearColor.g,
|
||||
clearColor.b, clearColor.a, clearStencil, clear, discard);
|
||||
}
|
||||
}
|
||||
|
||||
78
thermion_dart/lib/src/viewer/src/filament/filament.dart
Normal file
78
thermion_dart/lib/src/viewer/src/filament/filament.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/engine.dart';
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
class FilamentConfig<T, U> {
|
||||
final Backend backend;
|
||||
final T? renderCallback;
|
||||
final U? renderCallbackOwner;
|
||||
final U resourceLoader;
|
||||
final U? platform;
|
||||
final U? driver;
|
||||
final U? sharedContext;
|
||||
final String uberArchivePath;
|
||||
final int stereoscopicEyeCount;
|
||||
final bool disableHandleUseAfterFreeCheck;
|
||||
|
||||
FilamentConfig(
|
||||
{required this.backend,
|
||||
required this.resourceLoader,
|
||||
required this.uberArchivePath,
|
||||
this.renderCallback,
|
||||
this.renderCallbackOwner,
|
||||
this.platform,
|
||||
this.driver,
|
||||
this.sharedContext,
|
||||
this.stereoscopicEyeCount = 1,
|
||||
this.disableHandleUseAfterFreeCheck = false});
|
||||
}
|
||||
|
||||
abstract class FilamentApp<T> {
|
||||
final T engine;
|
||||
final T gltfAssetLoader;
|
||||
final T gltfResourceLoader;
|
||||
final T renderer;
|
||||
final T transformManager;
|
||||
final T lightManager;
|
||||
final T renderableManager;
|
||||
final T ubershaderMaterialProvider;
|
||||
|
||||
FilamentApp(
|
||||
{required this.engine,
|
||||
required this.gltfAssetLoader,
|
||||
required this.gltfResourceLoader,
|
||||
required this.renderer,
|
||||
required this.transformManager,
|
||||
required this.lightManager,
|
||||
required this.renderableManager,
|
||||
required this.ubershaderMaterialProvider
|
||||
});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height,
|
||||
{bool hasStencilBuffer = false});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createSwapChain(T handle, {bool hasStencilBuffer = false});
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroySwapChain(SwapChain swapChain);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroy();
|
||||
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(
|
||||
int width, int height, { covariant Texture? color, covariant Texture? depth });
|
||||
|
||||
}
|
||||
28
thermion_dart/lib/src/viewer/src/shared_types/engine.dart
Normal file
28
thermion_dart/lib/src/viewer/src/shared_types/engine.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
enum Backend {
|
||||
/// !< Automatically selects an appropriate driver for the platform.
|
||||
DEFAULT(0),
|
||||
|
||||
/// !< Selects the OpenGL/ES driver (default on Android)
|
||||
OPENGL(1),
|
||||
|
||||
/// !< Selects the Vulkan driver if the platform supports it (default on Linux/Windows)
|
||||
VULKAN(2),
|
||||
|
||||
/// !< Selects the Metal driver if the platform supports it (default on MacOS/iOS).
|
||||
METAL(3),
|
||||
|
||||
/// !< Selects the no-op driver for testing purposes.
|
||||
NOOP(4);
|
||||
|
||||
final int value;
|
||||
const Backend(this.value);
|
||||
|
||||
static Backend fromValue(int value) => switch (value) {
|
||||
0 => DEFAULT,
|
||||
1 => OPENGL,
|
||||
2 => VULKAN,
|
||||
3 => METAL,
|
||||
4 => NOOP,
|
||||
_ => throw ArgumentError("Unknown value for TBackend: $value"),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import 'package:thermion_dart/thermion_dart.dart';
|
||||
|
||||
final ThermionEntity FILAMENT_ENTITY_NULL = 0;
|
||||
18
thermion_dart/lib/src/viewer/src/shared_types/layers.dart
Normal file
18
thermion_dart/lib/src/viewer/src/shared_types/layers.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
const double kNear = 0.05;
|
||||
const double kFar = 1000.0;
|
||||
const double kFocalLength = 28.0;
|
||||
|
||||
enum VisibilityLayers {
|
||||
DEFAULT_ASSET(0),
|
||||
LAYER_1(1),
|
||||
LAYER_2(2),
|
||||
LAYER_3(3),
|
||||
LAYER_4(4),
|
||||
LAYER_5(5),
|
||||
BACKGROUND(6),
|
||||
OVERLAY(7);
|
||||
|
||||
final int value;
|
||||
const VisibilityLayers(this.value);
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ import 'package:thermion_dart/thermion_dart.dart';
|
||||
abstract class RenderTarget {
|
||||
Future<Texture> getColorTexture();
|
||||
Future<Texture> getDepthTexture();
|
||||
Future destroy();
|
||||
}
|
||||
|
||||
4
thermion_dart/lib/src/viewer/src/shared_types/scene.dart
Normal file
4
thermion_dart/lib/src/viewer/src/shared_types/scene.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
abstract class Scene {
|
||||
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:thermion_dart/src/viewer/src/shared_types/layers.dart';
|
||||
|
||||
import '../../utils/src/gizmo.dart';
|
||||
import 'shared_types/shared_types.dart';
|
||||
export 'shared_types/shared_types.dart';
|
||||
@@ -8,32 +10,12 @@ import 'package:vector_math/vector_math_64.dart';
|
||||
import 'dart:async';
|
||||
import 'package:animation_tools_dart/animation_tools_dart.dart';
|
||||
|
||||
const double kNear = 0.05;
|
||||
const double kFar = 1000.0;
|
||||
const double kFocalLength = 28.0;
|
||||
|
||||
enum VisibilityLayers {
|
||||
DEFAULT_ASSET(0),
|
||||
LAYER_1(1),
|
||||
LAYER_2(2),
|
||||
LAYER_3(3),
|
||||
LAYER_4(4),
|
||||
LAYER_5(5),
|
||||
BACKGROUND(6),
|
||||
OVERLAY(7);
|
||||
|
||||
final int value;
|
||||
const VisibilityLayers(this.value);
|
||||
}
|
||||
|
||||
final ThermionEntity FILAMENT_ENTITY_NULL = 0;
|
||||
|
||||
///
|
||||
/// A high-level interface for interacting with a 3D scene.
|
||||
/// This broadly maps to a single scene/view
|
||||
///
|
||||
abstract class ThermionViewer {
|
||||
///
|
||||
/// A Future that resolves when the underlying rendering context has been successfully created.
|
||||
///
|
||||
Future<bool> get initialized;
|
||||
|
||||
|
||||
///
|
||||
/// Whether the controller is currently rendering at [framerate].
|
||||
///
|
||||
@@ -47,7 +29,7 @@ abstract class ThermionViewer {
|
||||
///
|
||||
/// Render a single frame immediately.
|
||||
///
|
||||
Future render({covariant SwapChain? swapChain});
|
||||
Future render();
|
||||
|
||||
///
|
||||
/// Requests a single frame to be rendered. This is only intended to be used internally.
|
||||
@@ -60,31 +42,6 @@ abstract class ThermionViewer {
|
||||
Future<List<Uint8List>> capture(
|
||||
covariant List<({View view, SwapChain? swapChain, RenderTarget? renderTarget})> targets);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createHeadlessSwapChain(int width, int height);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<SwapChain> createSwapChain(int handle);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroySwapChain(covariant SwapChain swapChain);
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future<RenderTarget> createRenderTarget(
|
||||
int width, int height, { int? colorTextureHandle, int? depthTextureHandle });
|
||||
|
||||
///
|
||||
///
|
||||
///
|
||||
Future destroyRenderTarget(covariant RenderTarget renderTarget);
|
||||
|
||||
///
|
||||
///
|
||||
|
||||
@@ -312,12 +312,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setBloom(double bloom) {
|
||||
// TODO: implement setBloom
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setBoneTransform(
|
||||
ThermionEntity entity, int boneIndex, Matrix4 transform,
|
||||
@@ -768,12 +762,6 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<RenderTarget> createRenderTarget(int width, int height, int textureHandle) {
|
||||
// TODO: implement createRenderTarget
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setRenderTarget(covariant RenderTarget renderTarget) {
|
||||
// TODO: implement setRenderTarget
|
||||
@@ -799,13 +787,7 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
// TODO: implement createHeadlessSwapChain
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> capture({covariant SwapChain? swapChain, covariant View? view, covariant RenderTarget? renderTarget}) {
|
||||
// TODO: implement capture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
Future<SwapChain> createSwapChain(handle) {
|
||||
// TODO: implement createSwapChain
|
||||
@@ -1089,6 +1071,88 @@ class ThermionViewerStub extends ThermionViewer {
|
||||
// TODO: implement setParent
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LinearImage> createImage(int width, int height, int channels) {
|
||||
// TODO: implement createImage
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Texture> createTexture(int width, int height, {int depth = 1, int levels = 1, TextureSamplerType textureSamplerType = TextureSamplerType.SAMPLER_2D, TextureFormat textureFormat = TextureFormat.RGBA32F}) {
|
||||
// TODO: implement createTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<TextureSampler> createTextureSampler({TextureMinFilter minFilter = TextureMinFilter.LINEAR, TextureMagFilter magFilter = TextureMagFilter.LINEAR, TextureWrapMode wrapS = TextureWrapMode.CLAMP_TO_EDGE, TextureWrapMode wrapT = TextureWrapMode.CLAMP_TO_EDGE, TextureWrapMode wrapR = TextureWrapMode.CLAMP_TO_EDGE, double anisotropy = 0.0, TextureCompareMode compareMode = TextureCompareMode.NONE, TextureCompareFunc compareFunc = TextureCompareFunc.LESS_EQUAL}) {
|
||||
// TODO: implement createTextureSampler
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LinearImage> decodeImage(Uint8List data) {
|
||||
// TODO: implement decodeImage
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future destroyCamera(covariant Camera camera) {
|
||||
// TODO: implement destroyCamera
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isCastShadowsEnabled(ThermionEntity entity) {
|
||||
// TODO: implement isCastShadowsEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> isReceiveShadowsEnabled(ThermionEntity entity) {
|
||||
// TODO: implement isReceiveShadowsEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
// TODO: implement msPerFrame
|
||||
double get msPerFrame => throw UnimplementedError();
|
||||
|
||||
@override
|
||||
Future setCastShadows(ThermionEntity entity, bool castShadows) {
|
||||
// TODO: implement setCastShadows
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setClearOptions(Vector4 clearColor, int clearStencil, bool clear, bool discard) {
|
||||
// TODO: implement setClearOptions
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setReceiveShadows(ThermionEntity entity, bool receiveShadows) {
|
||||
// TODO: implement setReceiveShadows
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Uint8List>> capture(covariant List<({RenderTarget? renderTarget, SwapChain? swapChain, View view})> targets) {
|
||||
// TODO: implement capture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<RenderTarget> createRenderTarget(int width, int height, {int? colorTextureHandle, int? depthTextureHandle}) {
|
||||
// TODO: implement createRenderTarget
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setBloom(bool enabled, double strength) {
|
||||
// TODO: implement setBloom
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'package:vector_math/vector_math_64.dart';
|
||||
|
||||
import '../../../viewer.dart';
|
||||
|
||||
class ThermionWasmMaterialInstance extends MaterialInstance {
|
||||
@@ -94,4 +96,52 @@ class ThermionWasmMaterialInstance extends MaterialInstance {
|
||||
// TODO: implement setStencilWriteEnabled
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future dispose() {
|
||||
// TODO: implement dispose
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParameterBool(String name, bool value) {
|
||||
// TODO: implement setParameterBool
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParameterFloat3(String name, double x, double y, double z) {
|
||||
// TODO: implement setParameterFloat3
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParameterFloat3Array(String name, List<Vector3> data) {
|
||||
// TODO: implement setParameterFloat3Array
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setParameterTexture(String name, covariant Texture texture, covariant TextureSampler sampler) {
|
||||
// TODO: implement setParameterTexture
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setStencilReadMask(int mask) {
|
||||
// TODO: implement setStencilReadMask
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setStencilWriteMask(int mask) {
|
||||
// TODO: implement setStencilWriteMask
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
@override
|
||||
Future setTransparencyMode(TransparencyMode mode) {
|
||||
// TODO: implement setTransparencyMode
|
||||
throw UnimplementedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
// [context!, loader, null, uberArchivePath?.toJS].toJS,
|
||||
// null) as JSNumber;
|
||||
// await createSwapChain(width.ceil(), height.ceil());
|
||||
// updateViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0);
|
||||
// setViewportAndCameraProjection(width.ceil(), height.ceil(), 1.0);
|
||||
// _sceneManager = _module!.ccall("get_scene_manager", "void*",
|
||||
// ["void*".toJS].toJS, [_viewer!].toJS, null) as JSNumber;
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
// [_viewer!].toJS, null);
|
||||
// }
|
||||
|
||||
// void updateViewportAndCameraProjection(
|
||||
// void setViewportAndCameraProjection(
|
||||
// int width, int height, double scaleFactor) {
|
||||
// if (width == 0 || height == 0) {
|
||||
// throw Exception("Width/height must be greater than zero");
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/Frustum.h>
|
||||
#include <filament/ColorGrading.h>
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/IndexBuffer.h>
|
||||
#include <filament/RenderableManager.h>
|
||||
#include <filament/Renderer.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/VertexBuffer.h>
|
||||
#include <filament/View.h>
|
||||
#include <filament/LightManager.h>
|
||||
|
||||
#include <gltfio/AssetLoader.h>
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/ResourceLoader.h>
|
||||
|
||||
#include <camutils/Manipulator.h>
|
||||
|
||||
#include <utils/NameComponentManager.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/norm.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "scene/SceneManager.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
||||
|
||||
using namespace std::chrono;
|
||||
using namespace gltfio;
|
||||
using namespace camutils;
|
||||
|
||||
class FilamentViewer
|
||||
{
|
||||
|
||||
typedef int32_t EntityId;
|
||||
|
||||
public:
|
||||
FilamentViewer(const void *context, const ResourceLoaderWrapperImpl *const resourceLoaderWrapper, void *const platform = nullptr, const char *uberArchivePath = nullptr);
|
||||
~FilamentViewer();
|
||||
|
||||
View* createView();
|
||||
View* getViewAt(int index);
|
||||
|
||||
void loadSkybox(const char *const skyboxUri);
|
||||
void removeSkybox();
|
||||
|
||||
void loadIbl(const char *const iblUri, float intensity);
|
||||
void removeIbl();
|
||||
void rotateIbl(const math::mat3f &matrix);
|
||||
void createIbl(float r, float g, float b, float intensity);
|
||||
|
||||
void render(
|
||||
uint64_t frameTimeInNanos
|
||||
);
|
||||
void setFrameInterval(float interval);
|
||||
|
||||
void setMainCamera(View *view);
|
||||
EntityId getMainCamera();
|
||||
|
||||
float getCameraFov(bool horizontal);
|
||||
void setCameraFov(double fovDegrees, bool horizontal);
|
||||
|
||||
SwapChain* createSwapChain(const void *surface);
|
||||
SwapChain* createSwapChain(uint32_t width, uint32_t height);
|
||||
void destroySwapChain(SwapChain* swapChain);
|
||||
|
||||
RenderTarget* createRenderTarget(intptr_t colorTextureId, intptr_t depthTextureId, uint32_t width, uint32_t height);
|
||||
void destroyRenderTarget(RenderTarget* renderTarget);
|
||||
|
||||
Renderer *getRenderer();
|
||||
|
||||
std::map<SwapChain*, std::vector<View*>> _renderable;
|
||||
|
||||
void setRenderable(View* view, SwapChain* swapChain, bool renderable);
|
||||
|
||||
void setBackgroundColor(const float r, const float g, const float b, const float a);
|
||||
void setBackgroundImage(const char *resourcePath, bool fillHeight, uint32_t width, uint32_t height);
|
||||
void clearBackgroundImage();
|
||||
void setBackgroundImagePosition(float x, float y, bool clamp, uint32_t width, uint32_t height);
|
||||
|
||||
Engine* getEngine() {
|
||||
return _engine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void capture(View* view, uint8_t *out, bool useFence, SwapChain* swapChain, void (*onComplete)());
|
||||
void capture(View* view, uint8_t *out, bool useFence, SwapChain* swapChain, RenderTarget* renderTarget, void (*onComplete)());
|
||||
|
||||
SceneManager *const getSceneManager()
|
||||
{
|
||||
return (SceneManager *const)_sceneManager;
|
||||
}
|
||||
|
||||
SwapChain* getSwapChainAt(int index) {
|
||||
if(index < _swapChains.size()) {
|
||||
return _swapChains[index];
|
||||
}
|
||||
Log("Error: index %d is greater than available swapchains", index);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||
Scene *_scene = nullptr;
|
||||
Engine *_engine = nullptr;
|
||||
thermion::ThreadPool *_tp = nullptr;
|
||||
Renderer *_renderer = nullptr;
|
||||
SceneManager *_sceneManager = nullptr;
|
||||
std::vector<RenderTarget*> _renderTargets;
|
||||
std::vector<SwapChain*> _swapChains;
|
||||
std::vector<View*> _views;
|
||||
|
||||
std::mutex _renderMutex; // mutex to ensure thread safety when removing assets
|
||||
|
||||
Texture *_skyboxTexture = nullptr;
|
||||
Skybox *_skybox = nullptr;
|
||||
Texture *_iblTexture = nullptr;
|
||||
IndirectLight *_indirectLight = nullptr;
|
||||
|
||||
float _frameInterval = 1000.0 / 60.0;
|
||||
|
||||
// Camera properties
|
||||
Camera *_mainCamera = nullptr; // the default camera added to every scene. If you want the *active* camera, access via View.
|
||||
|
||||
// background image properties
|
||||
uint32_t _imageHeight = 0;
|
||||
uint32_t _imageWidth = 0;
|
||||
filament::math::mat4f _imageScale;
|
||||
Texture *_imageTexture = nullptr;
|
||||
Texture *_dummyImageTexture = nullptr;
|
||||
utils::Entity _imageEntity;
|
||||
VertexBuffer *_imageVb = nullptr;
|
||||
IndexBuffer *_imageIb = nullptr;
|
||||
Material *_imageMaterial = nullptr;
|
||||
TextureSampler _imageSampler;
|
||||
void loadKtx2Texture(std::string path, ResourceBuffer data);
|
||||
void loadKtxTexture(std::string path, ResourceBuffer data);
|
||||
void loadPngTexture(std::string path, ResourceBuffer data);
|
||||
void loadTextureFromPath(std::string path);
|
||||
void savePng(void *data, size_t size, int frameNumber);
|
||||
void createBackgroundImage();
|
||||
|
||||
|
||||
time_point_t _fpsCounterStartTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
|
||||
std::mutex _imageMutex;
|
||||
double _cumulativeAnimationUpdateTime = 0;
|
||||
int _frameCount = 0;
|
||||
int _skippedFrames = 0;
|
||||
};
|
||||
|
||||
struct FrameCallbackData
|
||||
{
|
||||
FilamentViewer *viewer;
|
||||
uint32_t frameNumber;
|
||||
};
|
||||
|
||||
}
|
||||
48
thermion_dart/native/include/RenderTicker.hpp
Normal file
48
thermion_dart/native/include/RenderTicker.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Renderer.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <math/vec3.h>
|
||||
#include <math/vec4.h>
|
||||
#include <math/mat3.h>
|
||||
#include <math/norm.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
|
||||
#include "scene/SceneManager.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> time_point_t;
|
||||
|
||||
using namespace std::chrono;
|
||||
|
||||
class RenderTicker
|
||||
{
|
||||
|
||||
public:
|
||||
RenderTicker(filament::Renderer renderer, thermion::SceneManager sceneManager) : mRenderer(renderer), mSceneManager(sceneManager) { }
|
||||
~RenderTicker();
|
||||
|
||||
void render(
|
||||
uint64_t frameTimeInNanos
|
||||
);
|
||||
void setRenderable(SwapChain *swapChain, View **view, uint8_t numViews);
|
||||
|
||||
private:
|
||||
std::mutex mMutex;
|
||||
Renderer *mRenderer = nullptr;
|
||||
SceneManager *mSceneManager = nullptr;
|
||||
std::vector<SwapChain*> mSwapChains;
|
||||
std::map<SwapChain*, std::vector<View*>> mRenderable;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ extern "C"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "APIExport.h"
|
||||
|
||||
typedef TRenderTicker TRenderTicker;
|
||||
typedef int32_t EntityId;
|
||||
typedef struct TCamera TCamera;
|
||||
typedef struct TEngine TEngine;
|
||||
@@ -110,6 +110,11 @@ extern "C"
|
||||
double z;
|
||||
} double3;
|
||||
|
||||
typedef struct {
|
||||
double3 col1;
|
||||
double3 col2;
|
||||
double3 col3;
|
||||
} double3x3;
|
||||
|
||||
typedef struct {
|
||||
double x;
|
||||
|
||||
@@ -21,10 +21,11 @@ enum TBackend {
|
||||
BACKEND_NOOP = 4, //!< Selects the no-op driver for testing purposes.
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Engine_create(TBackend backend);
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Engine_create(TBackend backend, void* platform, void* sharedContext, uint8_t stereoscopicEyeCount, bool disableHandleUseAfterFreeCheck);
|
||||
EMSCRIPTEN_KEEPALIVE TRenderer *Engine_createRenderer(TEngine *tEngine);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Engine_createSwapChain(TEngine *tEngine, void *window, uint64_t flags);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Engine_createHeadlessSwapChain(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags);
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChain(TEngine *tEngine, TSwapChain *tSwapChain);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_createCamera(TEngine* tEngine);
|
||||
EMSCRIPTEN_KEEPALIVE TView *Engine_createView(TEngine *tEngine);
|
||||
|
||||
@@ -23,6 +23,7 @@ EMSCRIPTEN_KEEPALIVE TFilamentAsset *GltfAssetLoader_load(
|
||||
uint8_t numInstances
|
||||
);
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialInstance *GltfAssetLoader_getMaterialInstance(TRenderableManager *tRenderableManager, TFilamentAsset *tAsset);
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialProvider *GltfAssetLoader_getMaterialProvider(TGltfAssetLoader *tAssetLoader);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
19
thermion_dart/native/include/c_api/TIndirectLight.h
Normal file
19
thermion_dart/native/include/c_api/TIndirectLight.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "APIExport.h"
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "TMaterialInstance.h"
|
||||
#include "TTexture.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "MathUtils.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void IndirectLight_setRotation(TIndirectLight TIndirectLight, double3x3 rotation);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -21,6 +21,11 @@ EMSCRIPTEN_KEEPALIVE TRenderTarget *RenderTarget_create(
|
||||
TTexture *depth
|
||||
);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTarget_destroy(
|
||||
TEngine *tEngine,
|
||||
TRenderTarget *tRenderTarget
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
17
thermion_dart/native/include/c_api/TRenderTicker.h
Normal file
17
thermion_dart/native/include/c_api/TRenderTicker.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "APIExport.h"
|
||||
#include "APIBoundaryTypes.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTicker *RenderTicker_create(TRenderer *tRenderer, TSceneManager *tSceneManager);
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTicker_render(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos);
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTicker_setRenderable(TRenderTicker *tFilamentRender, TSwapChain *swapChain, TView **views, uint8_t numViews);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -23,6 +23,13 @@ EMSCRIPTEN_KEEPALIVE void Renderer_readPixels(
|
||||
TPixelDataType tPixelDataType,
|
||||
uint8_t *out
|
||||
);
|
||||
EMSCRIPTEN_KEEPALIVE void Renderer_setFrameInterval(
|
||||
TRenderer *tRenderer,
|
||||
float headRoomRatio,
|
||||
float scaleRate,
|
||||
uint8_t history,
|
||||
uint8_t interval
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
#ifndef _FLUTTER_FILAMENT_API_H
|
||||
#define _FLUTTER_FILAMENT_API_H
|
||||
|
||||
#include "APIExport.h"
|
||||
#include "APIBoundaryTypes.h"
|
||||
#include "TMaterialInstance.h"
|
||||
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "MathUtils.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *const context, const void *const loader, void *const platform, const char *uberArchivePath);
|
||||
EMSCRIPTEN_KEEPALIVE TRenderer *Viewer_getRenderer(TViewer *tViewer);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget* Viewer_createRenderTarget(TViewer *viewer, intptr_t colorTextureId, intptr_t depthTextureId, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *viewer, TRenderTarget* tRenderTarget);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *viewer, const void *const window);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *viewer, uint32_t width, uint32_t height);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *viewer, TSwapChain* swapChain);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_render(
|
||||
TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *viewer,
|
||||
TView *view,
|
||||
TSwapChain *swapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
bool useFence,
|
||||
void (*callback)(void));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *viewer,
|
||||
TView *view,
|
||||
TSwapChain *swapChain,
|
||||
TRenderTarget *renderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
bool useFence,
|
||||
void (*callback)(void));
|
||||
EMSCRIPTEN_KEEPALIVE TView* Viewer_createView(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE TView* Viewer_getViewAt(TViewer *viewer, int index);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView);
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain* Viewer_getSwapChainAt(TViewer *tViewer, int index);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *viewer, TSwapChain *swapChain, TView* view, bool renderable);
|
||||
|
||||
// Engine
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer* viewer);
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId Viewer_getMainCamera(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadSkybox(TViewer *viewer, const char *skyboxPath);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_removeSkybox(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_removeIbl(TViewer *viewer);
|
||||
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 set_frame_interval(TViewer *viewer, float interval);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void queue_relative_position_update_world_axis(TSceneManager *sceneManager, EntityId entity, float viewportX, float viewportY, float x, float y, float z);
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *view, EntityId entity, float viewportX, float viewportY);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy();
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr);
|
||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*callback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform);
|
||||
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *view, EntityId entity);
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *view, EntityId entity, float *minX, float *minY, float *maxX, float *maxY);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,7 +1,5 @@
|
||||
#ifndef _DART_FILAMENT_FFI_API_H
|
||||
#define _DART_FILAMENT_FFI_API_H
|
||||
#pragma once
|
||||
|
||||
#include "ThermionDartApi.h"
|
||||
#include "TView.h"
|
||||
#include "TTexture.h"
|
||||
#include "TMaterialProvider.h"
|
||||
@@ -13,49 +11,30 @@ namespace thermion
|
||||
{
|
||||
#endif
|
||||
|
||||
///
|
||||
/// This header replicates most of the methods in ThermionDartApi.h.
|
||||
/// It represents the interface for:
|
||||
/// - invoking those methods that must be called on the main Filament engine thread
|
||||
/// - setting up a render loop
|
||||
///
|
||||
typedef int32_t EntityId;
|
||||
typedef void (*FilamentRenderCallback)(void *const owner);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderLoop_create();
|
||||
EMSCRIPTEN_KEEPALIVE void RenderLoop_destroy();
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
|
||||
void *const context,
|
||||
void *const platform,
|
||||
const char *uberArchivePath,
|
||||
const void *const loader,
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
void *const renderCallbackOwner,
|
||||
void (*callback)(TViewer *viewer));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createViewRenderThread(TViewer *viewer, void (*onComplete)(TView *tView));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyOnRenderThread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer, void *const surface, void (*onComplete)(TSwapChain *));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer, uint32_t width, uint32_t height, void (*onComplete)(TSwapChain *));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *view, TSwapChain *swapChain);
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView *view, TSwapChain *swapChain, uint8_t *out, bool useFence, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *swapChain, TRenderTarget *renderTarget, uint8_t *out, bool useFence, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIblRenderThread(TViewer *viewer, const char *iblPath, float intensity, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_removeIblRenderThread(TViewer *viewer, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t colorTexture, intptr_t depthTexture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *));
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTargetRenderThread(TViewer *viewer, TRenderTarget *tRenderTarget, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadSkyboxRenderThread(TViewer *viewer, const char *skyboxPath, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_removeSkyboxRenderThread(TViewer *viewer, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos,);
|
||||
// EMSCRIPTEN_KEEPALIVE void RenderLoop_addTask(TRenderLoop* tRenderLoop, void (*task)());
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread(TBackend backend, void (*onComplete)(TEngine *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread(
|
||||
TBackend backend,
|
||||
void* platform,
|
||||
void* sharedContext,
|
||||
uint8_t stereoscopicEyeCount,
|
||||
bool disableHandleUseAfterFreeCheck,
|
||||
void (*onComplete)(TEngine *)
|
||||
);
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createRendererRenderThread(TEngine *tEngine, void (*onComplete)(TRenderer *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createSwapChainRenderThread(TEngine *tEngine, void *window, uint64_t flags, void (*onComplete)(TSwapChain *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createHeadlessSwapChainRenderThread(TEngine *tEngine, uint32_t width, uint32_t height, uint64_t flags, void (*onComplete)(TSwapChain *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createViewRenderThread(TEngine *tEngine, void (*onComplete)(TView *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_buildMaterialRenderThread(TEngine *tEngine, const uint8_t *materialData, size_t length, void (*onComplete)(TMaterial *));
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroySkyboxRenderThread(TEngine *tEngine, TSkybox *tSkybox, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroyIndirectLightRenderThread(TEngine *tEngine, TIndirectLight *tIndirectLight, void (*onComplete)());
|
||||
@@ -98,13 +77,6 @@ namespace thermion
|
||||
EMSCRIPTEN_KEEPALIVE void View_setCameraRenderThread(TView *tView, TCamera *tCamera, void (*callback)());
|
||||
|
||||
FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
|
||||
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(TViewer *viewer, bool rendering, void (*onComplete)());
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(TViewer *viewer, float frameInterval);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(TViewer *viewer, const float r, const float g, const float b, const float a);
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(TViewer *viewer);
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(TViewer *viewer, const char *path, bool fillHeight, void (*onComplete)());
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(TViewer *viewer, float x, float y, bool clamp);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createGridRenderThread(TSceneManager *tSceneManager, TMaterial *tMaterial, void (*callback)(TSceneAsset *));
|
||||
|
||||
@@ -323,7 +295,7 @@ namespace thermion
|
||||
int boneIndex,
|
||||
const float *const transform,
|
||||
void (*callback)(bool));
|
||||
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(TViewer *viewer, bool enabled);
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(TSceneManager *sceneManager, EntityId entityId, void (*callback)());
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void GltfAssetLoader_createRenderThread(TEngine *tEngine, TMaterialProvider *tMaterialProvider, void (*callback)(TGltfAssetLoader *));
|
||||
@@ -345,4 +317,3 @@ namespace thermion
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _DART_FILAMENT_FFI_API_H
|
||||
|
||||
87
thermion_dart/native/include/rendering/RenderLoop.hpp
Normal file
87
thermion_dart/native/include/rendering/RenderLoop.hpp
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <deque>
|
||||
#include <future>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
#include "RenderTicker.hpp"
|
||||
|
||||
namespace thermion {
|
||||
|
||||
/**
|
||||
* @brief A render loop implementation that manages rendering on a separate thread.
|
||||
*
|
||||
* This class handles frame rendering requests, viewer creation, and maintains
|
||||
* a task queue for rendering operations.
|
||||
*/
|
||||
class RenderLoop {
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a new RenderLoop and starts the render thread.
|
||||
*/
|
||||
explicit RenderLoop();
|
||||
|
||||
/**
|
||||
* @brief Destroys the RenderLoop and stops the render thread.
|
||||
*/
|
||||
~RenderLoop();
|
||||
|
||||
/**
|
||||
* @brief Requests a frame to be rendered.
|
||||
*
|
||||
* @param callback Callback function to be called after rendering completes
|
||||
*/
|
||||
void requestFrame(void (*callback)());
|
||||
|
||||
/**
|
||||
* @brief Sets the render ticker used.
|
||||
*/
|
||||
void setRenderTicker(RenderTicker *renderTicker) {
|
||||
mRenderTicker = renderTicker;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Adds a task to the render thread's task queue.
|
||||
*
|
||||
* @param pt The packaged task to be executed
|
||||
* @return std::future<Rt> Future for the task result
|
||||
*/
|
||||
template <class Rt>
|
||||
auto add_task(std::packaged_task<Rt()>& pt) -> std::future<Rt>;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Main iteration of the render loop.
|
||||
*/
|
||||
void iter();
|
||||
|
||||
void (*_requestFrameRenderCallback)() = nullptr;
|
||||
bool _stop = false;
|
||||
std::mutex _mutex;
|
||||
std::mutex _taskMutex;
|
||||
std::condition_variable _cv;
|
||||
std::deque<std::function<void()>> _tasks;
|
||||
std::chrono::high_resolution_clock::time_point _lastFrameTime;
|
||||
int _frameCount = 0;
|
||||
float _accumulatedTime = 0.0f;
|
||||
float _fps = 0.0f;
|
||||
std::thread* t = nullptr;
|
||||
RenderTicker* mRenderTicker = nullptr;
|
||||
};
|
||||
|
||||
// Template implementation
|
||||
template <class Rt>
|
||||
auto RenderLoop::add_task(std::packaged_task<Rt()>& pt) -> std::future<Rt> {
|
||||
std::unique_lock<std::mutex> lock(_taskMutex);
|
||||
auto ret = pt.get_future();
|
||||
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
|
||||
std::move(pt))]
|
||||
{ (*pt)(); });
|
||||
_cv.notify_one();
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace thermion
|
||||
103
thermion_dart/native/src/RenderTicker.cpp
Normal file
103
thermion_dart/native/src/RenderTicker.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
#if __APPLE__
|
||||
#include "TargetConditionals.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
#endif
|
||||
|
||||
#include <filament/Camera.h>
|
||||
#include <filament/SwapChain.h>
|
||||
#include <backend/DriverEnums.h>
|
||||
#include <backend/platforms/OpenGLPlatform.h>
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <backend/platforms/PlatformWebGL.h>
|
||||
#include <emscripten/emscripten.h>
|
||||
#include <emscripten/bind.h>
|
||||
#include <emscripten/html5.h>
|
||||
#include <emscripten/threading.h>
|
||||
#include <emscripten/val.h>
|
||||
#endif
|
||||
#include <filament/Engine.h>
|
||||
|
||||
#include <filament/Options.h>
|
||||
#include <filament/Renderer.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <filament/RenderableManager.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <streambuf>
|
||||
#include <sstream>
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include <mutex>
|
||||
#include <iomanip>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
#include "RenderTicker.hpp"
|
||||
|
||||
namespace thermion
|
||||
{
|
||||
|
||||
using namespace filament;
|
||||
using namespace filament::math;
|
||||
using namespace utils;
|
||||
using namespace std::chrono;
|
||||
|
||||
using std::string;
|
||||
|
||||
static constexpr filament::math::float4 sFullScreenTriangleVertices[3] = {
|
||||
{-1.0f, -1.0f, 1.0f, 1.0f},
|
||||
{3.0f, -1.0f, 1.0f, 1.0f},
|
||||
{-1.0f, 3.0f, 1.0f, 1.0f}};
|
||||
|
||||
static const uint16_t sFullScreenTriangleIndices[3] = {0, 1, 2};
|
||||
|
||||
void RenderTicker::setRenderable(SwapChain *swapChain, View **views, uint8_t numViews) {
|
||||
{
|
||||
|
||||
std::lock_guard lock(mMutex);
|
||||
|
||||
auto swapChainViews = mRenderable[swapChain];
|
||||
|
||||
swapChainViews.clear();
|
||||
for(int i = 0; i < numViews; i++) {
|
||||
swapChainViews.push_back(views[i]);
|
||||
}
|
||||
|
||||
mRenderable[swapChain] = swapChainViews;
|
||||
}
|
||||
|
||||
void RenderTicker::render(uint64_t frameTimeInNanos)
|
||||
{
|
||||
std::lock_guard lock(mMutex);
|
||||
|
||||
mSceneManager->update();
|
||||
|
||||
for (auto swapChain : mSwapChains)
|
||||
{
|
||||
auto views = mRenderable[swapChain];
|
||||
if (views.size() > 0)
|
||||
{
|
||||
bool beginFrame = mRenderer->beginFrame(swapChain, frameTimeInNanos);
|
||||
if (beginFrame)
|
||||
{
|
||||
for (auto view : views)
|
||||
{
|
||||
mRenderer->render(view);
|
||||
}
|
||||
}
|
||||
mRenderer->endFrame();
|
||||
}
|
||||
}
|
||||
#ifdef __EMSCRIPTEN__
|
||||
_engine->execute();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
} // namespace thermion
|
||||
@@ -44,9 +44,17 @@ namespace thermion
|
||||
uint64_t TSWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER = filament::backend::SWAP_CHAIN_CONFIG_APPLE_CVPIXELBUFFER;
|
||||
uint64_t TSWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER = filament::backend::SWAP_CHAIN_CONFIG_HAS_STENCIL_BUFFER;
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Engine_create(TBackend backend)
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Engine_create(
|
||||
TBackend backend,
|
||||
void* platform,
|
||||
void* sharedContext,
|
||||
uint8_t stereoscopicEyeCount,
|
||||
bool disableHandleUseAfterFreeCheck)
|
||||
{
|
||||
auto *engine = filament::Engine::create(static_cast<filament::Engine::Backend>(backend));
|
||||
filament::Engine::Config config;
|
||||
config.stereoscopicEyeCount = stereoscopicEyeCount;
|
||||
config.disableHandleUseAfterFreeCheck = disableHandleUseAfterFreeCheck;
|
||||
auto *engine = filament::Engine::create(static_cast<filament::Engine::Backend>(backend), platform, sharedContext, &config);
|
||||
return reinterpret_cast<TEngine *>(engine);
|
||||
}
|
||||
|
||||
@@ -71,6 +79,12 @@ namespace thermion
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChain(TEngine *tEngine, TSwapChain *tSwapChain) {
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
auto *swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
engine->destroy(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Engine_createView(TEngine *tEngine)
|
||||
{
|
||||
auto *engine = reinterpret_cast<Engine *>(tEngine);
|
||||
@@ -279,12 +293,21 @@ namespace thermion
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroySkybox(TEngine *tEngine, TSkybox *tSkybox) {
|
||||
auto *engine = reinterpret_cast<filament::Engine *>(tEngine);
|
||||
auto *skybox = reinterpret_cast<filament::Skybox *>(tSkybox);
|
||||
if(skybox->getTexture()) {
|
||||
engine->destroy(skybox->getTexture());
|
||||
}
|
||||
engine->destroy(skybox);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroyIndirectLight(TEngine *tEngine, TIndirectLight *tIndirectLight) {
|
||||
auto *engine = reinterpret_cast<filament::Engine *>(tEngine);
|
||||
auto *indirectLight = reinterpret_cast<filament::IndirectLight *>(tIndirectLight);
|
||||
if(indirectLight->getReflectionsTexture()) {
|
||||
engine->destroy(indirectLight->getReflectionsTexture());
|
||||
}
|
||||
if(indirectLight->getIrradianceTexture()) {
|
||||
engine->destroy(indirectLight->getIrradianceTexture());
|
||||
}
|
||||
engine->destroy(indirectLight);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,6 +111,12 @@ EMSCRIPTEN_KEEPALIVE TMaterialInstance *GltfAssetLoader_getMaterialInstance(TRen
|
||||
return reinterpret_cast<TMaterialInstance*>(mi);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TMaterialProvider *GltfAssetLoader_getMaterialProvider(TGltfAssetLoader *tAssetLoader) {
|
||||
auto *assetLoader = reinterpret_cast<gltfio::AssetLoader>(tAssetLoader);
|
||||
auto materialProvider = assetLoader->getMaterialProvider();
|
||||
return reinterpret_cast<TMaterialProvider *>(&materialProvider);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
|
||||
41
thermion_dart/native/src/c_api/TIndirectLight.cpp
Normal file
41
thermion_dart/native/src/c_api/TIndirectLight.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include "c_api/TScene.h"
|
||||
|
||||
#include <filament/Engine.h>
|
||||
#include <filament/Fence.h>
|
||||
#include <filament/IndirectLight.h>
|
||||
#include <filament/Material.h>
|
||||
#include <filament/Scene.h>
|
||||
#include <filament/Skybox.h>
|
||||
#include <filament/Texture.h>
|
||||
#include <filament/TextureSampler.h>
|
||||
#include <filament/TransformManager.h>
|
||||
#include <filament/View.h>
|
||||
|
||||
#include <gltfio/FilamentAsset.h>
|
||||
#include <gltfio/FilamentInstance.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace thermion
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
using namespace filament;
|
||||
#endif
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void IndirectLight_setRotation(TIndirectLight *tIndirectLight, double3x3 rotation)
|
||||
{
|
||||
auto *indirectLight = reinterpret_cast<filament::IndirectLight *>(tIndirectLight);
|
||||
const filament::math::mat3f fRotation {
|
||||
filament::math::float3 { rotation.col1.x, rotation.col1.y, rotation.col1.z },
|
||||
filament::math::float3 { rotation.col2.x, rotation.col2.y, rotation.col2.z },
|
||||
filament::math::float3 { rotation.col3.x, rotation.col3.y, rotation.col3.z },
|
||||
};
|
||||
indirectLight->setRotation(fRotation);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -34,6 +34,16 @@ namespace thermion
|
||||
return reinterpret_cast<TRenderTarget *>(rt);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTarget_destroy(
|
||||
TEngine *tEngine,
|
||||
TRenderTarget *tRenderTarget
|
||||
) {
|
||||
auto engine = reinterpret_cast<filament::Engine *>(tEngine);
|
||||
auto *renderTarget = reinterpret_cast<filament::RenderTarget *>(tRenderTarget);
|
||||
engine->destroy(renderTarget);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
38
thermion_dart/native/src/c_api/TRenderTicker.cpp
Normal file
38
thermion_dart/native/src/c_api/TRenderTicker.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifdef _WIN32
|
||||
#include "ThermionWin32.h"
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "filament/LightManager.h"
|
||||
#include "Log.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "c_api/TRenderTicker.hpp"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTicker *RenderTicker_create(TRenderer *tRenderer, TSceneManager *tSceneManager) {
|
||||
auto *renderer = reinterpret_cast<filament::Renderer *>(tRenderer);
|
||||
auto *sceneManager = reinterpret_cast<thermion::SceneManager *>(tSceneManager);
|
||||
auto *renderTicker = new RenderTicker(renderer, sceneManager);
|
||||
return reinterpret_cast<TRenderTicker *>(renderTicker);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTicker_render(TRenderTicker *tRenderTicker, uint64_t frameTimeInNanos) {
|
||||
auto *renderTicker = reinterpret_cast<RenderTicker *>
|
||||
renderTicker->render(frameTimeInNanos);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTicker_setRenderable(TRenderTicker *tRenderTicker, TSwapChain *swapChain, TView **views, uint8_t numViews) {
|
||||
auto *renderTicker = reinterpret_cast<RenderTicker *>
|
||||
renderTicker->setRenderable(swapChain, views, numViews);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -61,6 +61,22 @@ EMSCRIPTEN_KEEPALIVE void Renderer_renderStandaloneView(TRenderer *tRenderer, TV
|
||||
renderer->renderStandaloneView(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Renderer_setFrameRateOptions(
|
||||
TRenderer *tRenderer,
|
||||
float headRoomRatio,
|
||||
float scaleRate,
|
||||
uint8_t history,
|
||||
uint8_t interval
|
||||
) {
|
||||
auto *renderer = reinterpret_cast<filament::Renderer *>(tRenderer);
|
||||
filament::Renderer::FrameRateOptions fro;
|
||||
fro.headRoomRatio = headRoomRatio;
|
||||
fro.scaleRate = scaleRate;
|
||||
fro.interval = interval;
|
||||
fro.interval = interval;
|
||||
renderer->setFrameRateOptions(fro);
|
||||
}
|
||||
|
||||
class CaptureCallbackHandler : public filament::backend::CallbackHandler
|
||||
{
|
||||
void post(void *user, Callback callback)
|
||||
|
||||
@@ -1,415 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#include "ThermionWin32.h"
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/emscripten.h>
|
||||
#endif
|
||||
|
||||
#include "filament/LightManager.h"
|
||||
#include "ResourceBuffer.hpp"
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "ThreadPool.hpp"
|
||||
|
||||
using namespace thermion;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
#include "c_api/ThermionDartApi.h"
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TViewer *Viewer_create(const void *context, const void *const loader, void *const platform, const char *uberArchivePath)
|
||||
{
|
||||
const auto *loaderImpl = new ResourceLoaderWrapperImpl((ResourceLoaderWrapper *)loader);
|
||||
auto viewer = new FilamentViewer(context, loaderImpl, platform, uberArchivePath);
|
||||
return reinterpret_cast<TViewer *>(viewer);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TEngine *Viewer_getEngine(TViewer *viewer)
|
||||
{
|
||||
auto *engine = reinterpret_cast<FilamentViewer *>(viewer)->getEngine();
|
||||
return reinterpret_cast<TEngine *>(engine);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderer *Viewer_getRenderer(TViewer *tViewer) {
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
return reinterpret_cast<TRenderer *>(viewer->getRenderer());
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TRenderTarget *Viewer_createRenderTarget(TViewer *tViewer, intptr_t colorTexture, intptr_t depthTexture, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = viewer->createRenderTarget(colorTexture, depthTexture, width, height);
|
||||
return reinterpret_cast<TRenderTarget *>(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTarget(TViewer *tViewer, TRenderTarget *tRenderTarget)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
viewer->destroyRenderTarget(renderTarget);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroy(TViewer *tViewer)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer*>(tViewer);
|
||||
delete viewer;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_color(TViewer *viewer, const float r, const float g, const float b, const float a)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundColor(r, g, b, a);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void clear_background_image(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->clearBackgroundImage();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image(TViewer *viewer, const char *path, bool fillHeight)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImage(path, fillHeight, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_background_image_position(TViewer *viewer, float x, float y, bool clamp)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setBackgroundImagePosition(x, y, clamp, 100, 100);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadSkybox(TViewer *viewer, const char *skyboxPath)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadSkybox(skyboxPath);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_removeSkybox(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeSkybox();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void create_ibl(TViewer *viewer, float r, float g, float b, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->createIbl(r, g, b, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_loadIbl(TViewer *viewer, const char *iblPath, float intensity)
|
||||
{
|
||||
((FilamentViewer *)viewer)->loadIbl(iblPath, intensity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_removeIbl(TViewer *viewer)
|
||||
{
|
||||
((FilamentViewer *)viewer)->removeIbl();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void rotate_ibl(TViewer *viewer, float *rotationMatrix)
|
||||
{
|
||||
math::mat3f matrix(rotationMatrix[0], rotationMatrix[1],
|
||||
rotationMatrix[2],
|
||||
rotationMatrix[3],
|
||||
rotationMatrix[4],
|
||||
rotationMatrix[5],
|
||||
rotationMatrix[6],
|
||||
rotationMatrix[7],
|
||||
rotationMatrix[8]);
|
||||
|
||||
((FilamentViewer *)viewer)->rotateIbl(matrix);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE int get_instance_count(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstanceCount(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_instances(TSceneManager *sceneManager, EntityId entityId, EntityId *out)
|
||||
{
|
||||
return ((SceneManager *)sceneManager)->getInstances(entityId, out);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setMainCamera(TViewer *tViewer, TView *tView)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->setMainCamera(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE EntityId Viewer_getMainCamera(TViewer *viewer)
|
||||
{
|
||||
return ((FilamentViewer *)viewer)->getMainCamera();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getFieldOfViewInDegrees(horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getFocalLength();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setProjection(fovInDegrees, aspect, near, far, horizontal ? Camera::Fov::HORIZONTAL : Camera::Fov::VERTICAL);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getModelMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getViewMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_culling_projection_matrix(TCamera *camera)
|
||||
{
|
||||
const auto &mat = reinterpret_cast<filament::Camera *>(camera)->getCullingProjectionMatrix();
|
||||
return convert_mat4_to_double4x4(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const auto &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setCustomProjection(mat, near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setLensProjection(TCamera *camera, double near, double far, double aspect, double focalLength)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setLensProjection(focalLength, aspect, near, far);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Camera_setModelMatrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setModelMatrix(convert_double4x4_to_mat4(matrix));
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getNear();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera)
|
||||
{
|
||||
auto cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
return cam->getCullingFar();
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *camera)
|
||||
{
|
||||
|
||||
const auto frustum = reinterpret_cast<filament::Camera *>(camera)->getFrustum();
|
||||
|
||||
const math::float4 *planes = frustum.getNormalizedPlanes();
|
||||
double *array = (double *)calloc(24, sizeof(double));
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
auto plane = planes[i];
|
||||
array[i * 4] = double(plane.x);
|
||||
array[i * 4 + 1] = double(plane.y);
|
||||
array[i * 4 + 2] = double(plane.z);
|
||||
array[i * 4 + 3] = double(plane.w);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float distance)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setFocusDistance(distance);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
cam->setExposure(aperture, shutterSpeed, sensitivity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix)
|
||||
{
|
||||
auto *cam = reinterpret_cast<filament::Camera *>(camera);
|
||||
const filament::math::mat4 &mat = convert_double4x4_to_mat4(matrix);
|
||||
cam->setModelMatrix(mat);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_render(
|
||||
TViewer *tViewer)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
viewer->render(0);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_setViewRenderable(TViewer *tViewer, TSwapChain *tSwapChain, TView *tView, bool renderable)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->setRenderable(view, swapChain, renderable);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_capture(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
uint8_t *pixelBuffer,
|
||||
bool useFence,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
useFence = true;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTarget(
|
||||
TViewer *tViewer,
|
||||
TView *tView,
|
||||
TSwapChain *tSwapChain,
|
||||
TRenderTarget *tRenderTarget,
|
||||
uint8_t *pixelBuffer,
|
||||
bool useFence,
|
||||
void (*callback)(void))
|
||||
{
|
||||
#ifdef __EMSCRIPTEN__
|
||||
useFence = true;
|
||||
#endif
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
auto renderTarget = reinterpret_cast<RenderTarget *>(tRenderTarget);
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
viewer->capture(view, pixelBuffer, useFence, swapChain, renderTarget, callback);
|
||||
};
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void set_frame_interval(
|
||||
TViewer *viewer,
|
||||
float frameInterval)
|
||||
{
|
||||
((FilamentViewer *)viewer)->setFrameInterval(frameInterval);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChain(TViewer *tViewer, TSwapChain *tSwapChain)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = reinterpret_cast<SwapChain *>(tSwapChain);
|
||||
viewer->destroySwapChain(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createHeadlessSwapChain(TViewer *tViewer, uint32_t width, uint32_t height)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(width, height);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_createSwapChain(TViewer *tViewer, const void *const window)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->createSwapChain(window);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSwapChain *Viewer_getSwapChainAt(TViewer *tViewer, int index)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto swapChain = viewer->getSwapChainAt(index);
|
||||
return reinterpret_cast<TSwapChain *>(swapChain);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_createView(TViewer *tViewer)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->createView();
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TView *Viewer_getViewAt(TViewer *tViewer, int32_t index)
|
||||
{
|
||||
auto viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto view = viewer->getViewAt(index);
|
||||
return reinterpret_cast<TView *>(view);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE TSceneManager *Viewer_getSceneManager(TViewer *tViewer)
|
||||
{
|
||||
auto *viewer = reinterpret_cast<FilamentViewer *>(tViewer);
|
||||
auto *sceneManager = viewer->getSceneManager();
|
||||
return reinterpret_cast<TSceneManager *>(sceneManager);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void queue_position_update_from_viewport_coords(TSceneManager *sceneManager, TView *tView, EntityId entity, float viewportX, float viewportY)
|
||||
{
|
||||
auto *view = reinterpret_cast<View *>(tView);
|
||||
((SceneManager *)sceneManager)->queueRelativePositionUpdateFromViewportVector(view, entity, viewportX, viewportY);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void ios_dummy()
|
||||
{
|
||||
Log("Dummy called");
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_filament_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void add_collision_component(TSceneManager *sceneManager, EntityId entityId, void (*onCollisionCallback)(const EntityId entityId1, const EntityId entityId2), bool affectsCollidingTransform)
|
||||
{
|
||||
((SceneManager *)sceneManager)->addCollisionComponent(entityId, onCollisionCallback, affectsCollidingTransform);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void remove_collision_component(TSceneManager *sceneManager, EntityId entityId)
|
||||
{
|
||||
((SceneManager *)sceneManager)->removeCollisionComponent(entityId);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void test_collisions(TSceneManager *sceneManager, EntityId entity)
|
||||
{
|
||||
((SceneManager *)sceneManager)->testCollisions(entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE Aabb2 get_bounding_box(TSceneManager *sceneManager, TView *tView, EntityId entity)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
return ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void get_bounding_box_to_out(TSceneManager *sceneManager, TView *tView, EntityId entity, float *minX, float *minY, float *maxX, float *maxY)
|
||||
{
|
||||
auto view = reinterpret_cast<View *>(tView);
|
||||
auto box = ((SceneManager *)sceneManager)->getScreenSpaceBoundingBox(view, entity);
|
||||
*minX = box.minX;
|
||||
*minY = box.minY;
|
||||
*maxX = box.maxX;
|
||||
*maxY = box.maxY;
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void thermion_flutter_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <filament/LightManager.h>
|
||||
|
||||
#include "c_api/APIBoundaryTypes.h"
|
||||
|
||||
#include "c_api/TAnimationManager.h"
|
||||
#include "c_api/TEngine.h"
|
||||
#include "c_api/TGltfAssetLoader.h"
|
||||
@@ -19,7 +18,8 @@
|
||||
#include "c_api/TView.h"
|
||||
#include "c_api/ThermionDartRenderThreadApi.h"
|
||||
|
||||
#include "FilamentViewer.hpp"
|
||||
#include "RenderTicker.hpp"
|
||||
#include "rendering/RenderLoop.hpp"
|
||||
#include "Log.hpp"
|
||||
|
||||
#include "ThreadPool.hpp"
|
||||
@@ -28,165 +28,6 @@ using namespace thermion;
|
||||
using namespace std::chrono_literals;
|
||||
#include <time.h>
|
||||
|
||||
class RenderLoop
|
||||
{
|
||||
public:
|
||||
explicit RenderLoop()
|
||||
{
|
||||
srand(time(NULL));
|
||||
t = new std::thread([this]()
|
||||
{ start(); });
|
||||
}
|
||||
|
||||
~RenderLoop()
|
||||
{
|
||||
TRACE("Destroying RenderLoop");
|
||||
_stop = true;
|
||||
_cv.notify_one();
|
||||
TRACE("Joining RenderLoop thread..");
|
||||
t->join();
|
||||
TRACE("RenderLoop destructor complete");
|
||||
}
|
||||
|
||||
void start()
|
||||
{
|
||||
while (!_stop)
|
||||
{
|
||||
iter();
|
||||
}
|
||||
}
|
||||
|
||||
void destroyViewer() {
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
if(viewer) {
|
||||
Viewer_destroy(viewer);
|
||||
}
|
||||
viewer = nullptr;
|
||||
_renderCallback = nullptr;
|
||||
_renderCallbackOwner = nullptr;
|
||||
|
||||
});
|
||||
auto fut = add_task(lambda);
|
||||
fut.wait();
|
||||
}
|
||||
|
||||
void createViewer(
|
||||
void *const context,
|
||||
void *const platform,
|
||||
const char *uberArchivePath,
|
||||
const void *const loader,
|
||||
void (*renderCallback)(void *),
|
||||
void *const owner,
|
||||
void (*callback)(TViewer *))
|
||||
{
|
||||
_renderCallback = renderCallback;
|
||||
_renderCallbackOwner = owner;
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{
|
||||
if(viewer) {
|
||||
Viewer_destroy(viewer);
|
||||
}
|
||||
viewer = Viewer_create(context, loader, platform, uberArchivePath);
|
||||
callback(viewer); });
|
||||
add_task(lambda);
|
||||
}
|
||||
|
||||
void requestFrame(void (*callback)())
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
this->_requestFrameRenderCallback = callback;
|
||||
_cv.notify_one();
|
||||
}
|
||||
|
||||
void iter()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (_requestFrameRenderCallback)
|
||||
{
|
||||
doRender();
|
||||
lock.unlock();
|
||||
this->_requestFrameRenderCallback();
|
||||
this->_requestFrameRenderCallback = nullptr;
|
||||
|
||||
// Calculate and print FPS
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - _lastFrameTime).count();
|
||||
_lastFrameTime = currentTime;
|
||||
|
||||
_frameCount++;
|
||||
_accumulatedTime += deltaTime;
|
||||
|
||||
if (_accumulatedTime >= 1.0f) // Update FPS every second
|
||||
{
|
||||
_fps = _frameCount / _accumulatedTime;
|
||||
// std::cout << "FPS: " << _fps << std::endl;
|
||||
_frameCount = 0;
|
||||
_accumulatedTime = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> taskLock(_taskMutex);
|
||||
|
||||
if (!_tasks.empty())
|
||||
{
|
||||
auto task = std::move(_tasks.front());
|
||||
_tasks.pop_front();
|
||||
taskLock.unlock();
|
||||
task();
|
||||
taskLock.lock();
|
||||
}
|
||||
|
||||
_cv.wait_for(taskLock, std::chrono::microseconds(2000), [this]
|
||||
{ return !_tasks.empty() || _stop; });
|
||||
}
|
||||
|
||||
void doRender()
|
||||
{
|
||||
Viewer_render(viewer);
|
||||
if (_renderCallback)
|
||||
{
|
||||
_renderCallback(_renderCallbackOwner);
|
||||
}
|
||||
}
|
||||
|
||||
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
|
||||
{
|
||||
_frameIntervalInMicroseconds = static_cast<int>(1000.0f * frameIntervalInMilliseconds);
|
||||
}
|
||||
|
||||
template <class Rt>
|
||||
auto add_task(std::packaged_task<Rt()> &pt) -> std::future<Rt>
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_taskMutex);
|
||||
auto ret = pt.get_future();
|
||||
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
|
||||
std::move(pt))]
|
||||
{ (*pt)(); });
|
||||
_cv.notify_one();
|
||||
return ret;
|
||||
}
|
||||
|
||||
TViewer *viewer = std::nullptr_t();
|
||||
|
||||
private:
|
||||
void (*_requestFrameRenderCallback)() = nullptr;
|
||||
bool _stop = false;
|
||||
int _frameIntervalInMicroseconds = 1000000 / 60;
|
||||
std::mutex _mutex;
|
||||
std::mutex _taskMutex;
|
||||
std::condition_variable _cv;
|
||||
void (*_renderCallback)(void *const) = nullptr;
|
||||
void *_renderCallbackOwner = nullptr;
|
||||
std::deque<std::function<void()>> _tasks;
|
||||
std::chrono::high_resolution_clock::time_point _lastFrameTime;
|
||||
int _frameCount = 0;
|
||||
float _accumulatedTime = 0.0f;
|
||||
float _fps = 0.0f;
|
||||
std::thread *t = nullptr;
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
@@ -205,145 +46,21 @@ extern "C"
|
||||
TRACE("RenderLoop_destroy");
|
||||
if (_rl)
|
||||
{
|
||||
_rl->destroyViewer();
|
||||
_rl = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createOnRenderThread(
|
||||
void *const context, void *const platform, const char *uberArchivePath,
|
||||
const void *const loader,
|
||||
void (*renderCallback)(void *const renderCallbackOwner),
|
||||
void *const renderCallbackOwner,
|
||||
void (*callback)(TViewer *))
|
||||
{
|
||||
TRACE("Viewer_createOnRenderThread");
|
||||
_rl->createViewer(
|
||||
context,
|
||||
platform,
|
||||
uberArchivePath,
|
||||
loader,
|
||||
renderCallback,
|
||||
renderCallbackOwner,
|
||||
callback
|
||||
);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyOnRenderThread(TViewer *viewer)
|
||||
{
|
||||
TRACE("Viewer_destroyOnRenderThread");
|
||||
if (!_rl)
|
||||
{
|
||||
Log("Warning - cannot destroy viewer, no RenderLoop has been created");
|
||||
} else {
|
||||
_rl->destroyViewer();
|
||||
}
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createViewRenderThread(TViewer *viewer, void (*onComplete)(TView *tView)) {
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void RenderTicker_renderRenderThread(TRenderTicker *tRenderTicker, , uint64_t frameTimeInNanos, void (*onComplete)()) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto *view = Viewer_createView(viewer);
|
||||
onComplete(view);
|
||||
RenderTicker_render(tRenderTicker, frameTimeInNanos);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createHeadlessSwapChainRenderThread(TViewer *viewer,
|
||||
uint32_t width,
|
||||
uint32_t height,
|
||||
void (*onComplete)(TSwapChain *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto *swapChain = Viewer_createHeadlessSwapChain(viewer, width, height);
|
||||
onComplete(swapChain);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createSwapChainRenderThread(TViewer *viewer,
|
||||
void *const surface,
|
||||
void (*onComplete)(TSwapChain *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto *swapChain = Viewer_createSwapChain(viewer, surface);
|
||||
onComplete(swapChain);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroySwapChainRenderThread(TViewer *viewer, TSwapChain *swapChain, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_destroySwapChain(viewer, swapChain);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_requestFrameRenderThread(TViewer *viewer, void (*onComplete)())
|
||||
{
|
||||
if (!_rl)
|
||||
{
|
||||
Log("No render loop!"); // PANIC?
|
||||
}
|
||||
else
|
||||
{
|
||||
_rl->requestFrame(onComplete);
|
||||
}
|
||||
}
|
||||
|
||||
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 Viewer_removeIblRenderThread(TViewer *viewer, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_removeIbl(viewer);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_createRenderTargetRenderThread(TViewer *viewer, intptr_t colorTexture, intptr_t depthTexture, uint32_t width, uint32_t height, void (*onComplete)(TRenderTarget *))
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
auto renderTarget = Viewer_createRenderTarget(viewer, colorTexture, depthTexture, width, height);
|
||||
onComplete(renderTarget);
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_destroyRenderTargetRenderThread(TViewer *tViewer, TRenderTarget *tRenderTarget, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Viewer_destroyRenderTarget(tViewer, tRenderTarget);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createRenderThread(TBackend backend, void (*onComplete)(TEngine *)) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
@@ -383,6 +100,16 @@ extern "C"
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroySwapChainRenderThread(TEngine *tEngine, TSwapChain *tSwapChain, void (*onComplete)()) {
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{
|
||||
Engine_destroySwapChain(tEngine);
|
||||
onComplete();
|
||||
});
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_createCameraRenderThread(TEngine* tEngine, void (*onComplete)(TCamera *)) {
|
||||
std::packaged_task<void()> lambda(
|
||||
@@ -446,6 +173,7 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Engine_destroyMaterialRenderThread(TEngine *tEngine, TMaterial *tMaterial, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
@@ -592,15 +320,6 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
set_frame_interval_render_thread(TViewer *viewer, float frameIntervalInMilliseconds)
|
||||
{
|
||||
_rl->setFrameIntervalInMilliseconds(frameIntervalInMilliseconds);
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ ((FilamentViewer *)viewer)->setFrameInterval(frameIntervalInMilliseconds); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_renderRenderThread(TViewer *viewer, TView *tView, TSwapChain *tSwapChain)
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
@@ -608,30 +327,6 @@ extern "C"
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, uint8_t *pixelBuffer, bool useFence, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ Viewer_capture(viewer, view, tSwapChain, pixelBuffer, useFence, onComplete); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void Viewer_captureRenderTargetRenderThread(TViewer *viewer, TView *view, TSwapChain *tSwapChain, TRenderTarget *tRenderTarget, uint8_t *pixelBuffer, bool useFence, void (*onComplete)())
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
{ Viewer_captureRenderTarget(viewer, view, tSwapChain, tRenderTarget, pixelBuffer, useFence, onComplete); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void
|
||||
set_background_color_render_thread(TViewer *viewer, const float r, const float g,
|
||||
const float b, const float a)
|
||||
{
|
||||
std::packaged_task<void()> lambda(
|
||||
[=]() mutable
|
||||
{ set_background_color(viewer, r, g, b, a); });
|
||||
auto fut = _rl->add_task(lambda);
|
||||
}
|
||||
|
||||
EMSCRIPTEN_KEEPALIVE void SceneManager_createGridRenderThread(TSceneManager *tSceneManager, TMaterial *tMaterial, void (*callback)(TSceneAsset *))
|
||||
{
|
||||
std::packaged_task<void()> lambda([=]() mutable
|
||||
|
||||
83
thermion_dart/native/src/rendering/RenderLoop.cpp
Normal file
83
thermion_dart/native/src/rendering/RenderLoop.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
#include "RenderLoop.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "Log.hpp"
|
||||
|
||||
namespace thermion {
|
||||
|
||||
RenderLoop::RenderLoop()
|
||||
{
|
||||
srand(time(NULL));
|
||||
t = new std::thread([this]() {
|
||||
while (!_stop) {
|
||||
iter();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
RenderLoop::~RenderLoop()
|
||||
{
|
||||
TRACE("Destroying RenderLoop");
|
||||
_stop = true;
|
||||
_cv.notify_one();
|
||||
TRACE("Joining RenderLoop thread..");
|
||||
t->join();
|
||||
delete t;
|
||||
|
||||
TRACE("RenderLoop destructor complete");
|
||||
}
|
||||
|
||||
void RenderLoop::requestFrame(void (*callback)())
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
this->_requestFrameRenderCallback = callback;
|
||||
_cv.notify_one();
|
||||
}
|
||||
|
||||
void RenderLoop::iter()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(_mutex);
|
||||
if (_requestFrameRenderCallback)
|
||||
{
|
||||
mRenderTicker->render();
|
||||
lock.unlock();
|
||||
this->_requestFrameRenderCallback();
|
||||
this->_requestFrameRenderCallback = nullptr;
|
||||
|
||||
// Calculate and print FPS
|
||||
auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - _lastFrameTime).count();
|
||||
_lastFrameTime = currentTime;
|
||||
|
||||
_frameCount++;
|
||||
_accumulatedTime += deltaTime;
|
||||
|
||||
if (_accumulatedTime >= 1.0f) // Update FPS every second
|
||||
{
|
||||
_fps = _frameCount / _accumulatedTime;
|
||||
_frameCount = 0;
|
||||
_accumulatedTime = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> taskLock(_taskMutex);
|
||||
|
||||
if (!_tasks.empty())
|
||||
{
|
||||
auto task = std::move(_tasks.front());
|
||||
_tasks.pop_front();
|
||||
taskLock.unlock();
|
||||
task();
|
||||
taskLock.lock();
|
||||
}
|
||||
|
||||
_cv.wait_for(taskLock, std::chrono::microseconds(2000), [this]
|
||||
{ return !_tasks.empty() || _stop; });
|
||||
}
|
||||
|
||||
|
||||
} // namespace thermion
|
||||
Reference in New Issue
Block a user