rename from *FFI to *RenderThread, return bool from render() to check frame timings, update render loop to wait on condition variable, add requestFrame() method

This commit is contained in:
Nick Fisher
2024-09-21 10:21:46 +08:00
parent 493d547c7b
commit ab1de78b74
14 changed files with 1170 additions and 1135 deletions

View File

@@ -1,11 +1,11 @@
output: '../lib/thermion_dart/viewer/ffi/thermion_dart.g.dart'
headers:
entry-points:
- '../native/include/ThermionDartFFIApi.h'
- '../native/include/ThermionDartRenderThreadApi.h'
- '../native/include/ThermionDartApi.h'
- '../native/include/ResourceBuffer.h'
include-directives:
- '../native/include/ThermionDartFFIApi.h'
- '../native/include/ThermionDartRenderThreadApi.h'
- '../native/include/ThermionDartApi.h'
- '../native/include/ResourceBuffer.h'
- '../native/include/APIBoundaryTypes.h'

View File

@@ -819,8 +819,8 @@ external ffi.Pointer<ffi.Double> get_camera_frustum(
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TCamera>, double4x4, ffi.Double,
ffi.Double)>(isLeaf: true)
ffi.Void Function(
ffi.Pointer<TCamera>, double4x4, ffi.Double, ffi.Double)>(isLeaf: true)
external void set_camera_projection_matrix(
ffi.Pointer<TCamera> camera,
double4x4 matrix,
@@ -829,8 +829,8 @@ external void set_camera_projection_matrix(
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TCamera>, ffi.Double, ffi.Double,
ffi.Double, ffi.Double, ffi.Bool)>(isLeaf: true)
ffi.Void Function(ffi.Pointer<TCamera>, ffi.Double, ffi.Double, ffi.Double,
ffi.Double, ffi.Bool)>(isLeaf: true)
external void set_camera_projection_from_fov(
ffi.Pointer<TCamera> camera,
double fovInDegrees,
@@ -857,8 +857,8 @@ external double get_camera_fov(
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TCamera>, ffi.Double, ffi.Double,
ffi.Double, ffi.Double)>(isLeaf: true)
ffi.Void Function(ffi.Pointer<TCamera>, ffi.Double, ffi.Double, ffi.Double,
ffi.Double)>(isLeaf: true)
external void set_camera_lens_projection(
ffi.Pointer<TCamera> camera,
double near,
@@ -884,6 +884,17 @@ external void set_camera_manipulator_options(
double zoomSpeed,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TCamera>, double4x4, double4x4, ffi.Double,
ffi.Double)>(isLeaf: true)
external void Camera_setCustomProjectionWithCulling(
ffi.Pointer<TCamera> camera,
double4x4 projectionMatrix,
double4x4 projectionMatrixForCulling,
double near,
double far,
);
@ffi.Native<
ffi.Int Function(
ffi.Pointer<ffi.Void>, EntityId, ffi.Pointer<ffi.Char>)>(isLeaf: true)
@@ -1339,7 +1350,7 @@ external void MaterialInstance_setDepthCulling(
ffi.NativeFunction<
ffi.Void Function(
ffi.Pointer<ffi.Void> viewer)>>)>(isLeaf: true)
external void create_filament_viewer_ffi(
external void create_filament_viewer_render_thread(
ffi.Pointer<ffi.Void> context,
ffi.Pointer<ffi.Void> platform,
ffi.Pointer<ffi.Char> uberArchivePath,
@@ -1361,7 +1372,7 @@ external void create_filament_viewer_ffi(
ffi.Uint32,
ffi.Uint32,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void create_swap_chain_ffi(
external void create_swap_chain_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.Void> surface,
int width,
@@ -1372,7 +1383,7 @@ external void create_swap_chain_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void destroy_swap_chain_ffi(
external void destroy_swap_chain_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@@ -1380,7 +1391,7 @@ external void destroy_swap_chain_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.IntPtr, ffi.Uint32, ffi.Uint32,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void create_render_target_ffi(
external void create_render_target_render_thread(
ffi.Pointer<ffi.Void> viewer,
int nativeTextureId,
int width,
@@ -1389,19 +1400,19 @@ external void create_render_target_ffi(
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void destroy_filament_viewer_ffi(
external void destroy_filament_viewer_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void render_ffi(
external void render_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Uint8>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void capture_ffi(
external void capture_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.Uint8> out,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
@@ -1416,14 +1427,19 @@ external FilamentRenderCallback make_render_callback_fn_pointer(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Bool,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void set_rendering_ffi(
external void set_rendering_render_thread(
ffi.Pointer<ffi.Void> viewer,
bool rendering,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void request_frame_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Float)>(isLeaf: true)
external void set_frame_interval_ffi(
external void set_frame_interval_render_thread(
ffi.Pointer<ffi.Void> viewer,
double frameInterval,
);
@@ -1431,7 +1447,7 @@ external void set_frame_interval_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Float, ffi.Float, ffi.Float,
ffi.Float)>(isLeaf: true)
external void set_background_color_ffi(
external void set_background_color_render_thread(
ffi.Pointer<ffi.Void> viewer,
double r,
double g,
@@ -1440,14 +1456,14 @@ external void set_background_color_ffi(
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void clear_background_image_ffi(
external void clear_background_image_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Char>, ffi.Bool,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void set_background_image_ffi(
external void set_background_image_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.Char> path,
bool fillHeight,
@@ -1457,7 +1473,7 @@ external void set_background_image_ffi(
@ffi.Native<
ffi.Void Function(
ffi.Pointer<ffi.Void>, ffi.Float, ffi.Float, ffi.Bool)>(isLeaf: true)
external void set_background_image_position_ffi(
external void set_background_image_position_render_thread(
ffi.Pointer<ffi.Void> viewer,
double x,
double y,
@@ -1465,13 +1481,13 @@ external void set_background_image_position_ffi(
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Int)>(isLeaf: true)
external void set_tone_mapping_ffi(
external void set_tone_mapping_render_thread(
ffi.Pointer<ffi.Void> viewer,
int toneMapping,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Float)>(isLeaf: true)
external void set_bloom_ffi(
external void set_bloom_render_thread(
ffi.Pointer<ffi.Void> viewer,
double strength,
);
@@ -1479,7 +1495,7 @@ external void set_bloom_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void load_skybox_ffi(
external void load_skybox_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.Char> skyboxPath,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
@@ -1488,19 +1504,19 @@ external void load_skybox_ffi(
@ffi.Native<
ffi.Void Function(
ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Char>, ffi.Float)>(isLeaf: true)
external void load_ibl_ffi(
external void load_ibl_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.Char> iblPath,
double intensity,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void remove_skybox_ffi(
external void remove_skybox_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void remove_ibl_ffi(
external void remove_ibl_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@@ -1525,7 +1541,7 @@ external void remove_ibl_ffi(
ffi.Bool,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void add_light_ffi(
external void add_light_render_thread(
ffi.Pointer<ffi.Void> viewer,
int type,
double colour,
@@ -1547,13 +1563,13 @@ external void add_light_ffi(
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId)>(isLeaf: true)
external void remove_light_ffi(
external void remove_light_render_thread(
ffi.Pointer<ffi.Void> viewer,
int entityId,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>)>(isLeaf: true)
external void clear_lights_ffi(
external void clear_lights_render_thread(
ffi.Pointer<ffi.Void> viewer,
);
@@ -1565,7 +1581,7 @@ external void clear_lights_ffi(
ffi.Bool,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void load_glb_ffi(
external void load_glb_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
ffi.Pointer<ffi.Char> assetPath,
int numInstances,
@@ -1584,7 +1600,7 @@ external void load_glb_ffi(
ffi.Int,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void load_glb_from_buffer_ffi(
external void load_glb_from_buffer_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
ffi.Pointer<ffi.Uint8> data,
int length,
@@ -1603,7 +1619,7 @@ external void load_glb_from_buffer_ffi(
ffi.Bool,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void load_gltf_ffi(
external void load_gltf_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
ffi.Pointer<ffi.Char> assetPath,
ffi.Pointer<ffi.Char> relativePath,
@@ -1615,7 +1631,7 @@ external void load_gltf_ffi(
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void create_instance_ffi(
external void create_instance_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int entityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
@@ -1624,7 +1640,7 @@ external void create_instance_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void remove_entity_ffi(
external void remove_entity_render_thread(
ffi.Pointer<ffi.Void> viewer,
int asset,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> callback,
@@ -1633,7 +1649,7 @@ external void remove_entity_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void clear_entities_ffi(
external void clear_entities_render_thread(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> callback,
);
@@ -1645,7 +1661,7 @@ external void clear_entities_ffi(
ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Bool)>>)>(
isLeaf: true)
external void set_camera_ffi(
external void set_camera_render_thread(
ffi.Pointer<ffi.Void> viewer,
int asset,
ffi.Pointer<ffi.Char> nodeName,
@@ -1655,7 +1671,7 @@ external void set_camera_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Float>, ffi.Int)>(isLeaf: true)
external void apply_weights_ffi(
external void apply_weights_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
ffi.Pointer<ffi.Char> entityName,
@@ -1666,7 +1682,7 @@ external void apply_weights_ffi(
@ffi.Native<
ffi.Void Function(
ffi.Pointer<ffi.Void>, EntityId, ffi.Int, ffi.Int)>(isLeaf: true)
external void set_animation_frame_ffi(
external void set_animation_frame_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
int animationIndex,
@@ -1675,7 +1691,7 @@ external void set_animation_frame_ffi(
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId, ffi.Int)>(
isLeaf: true)
external void stop_animation_ffi(
external void stop_animation_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
int index,
@@ -1685,7 +1701,7 @@ external void stop_animation_ffi(
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Int)>>)>(
isLeaf: true)
external void get_animation_count_ffi(
external void get_animation_count_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Int)>> callback,
@@ -1698,7 +1714,7 @@ external void get_animation_count_ffi(
ffi.Pointer<ffi.Char>,
ffi.Int,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void get_animation_name_ffi(
external void get_animation_name_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
ffi.Pointer<ffi.Char> outPtr,
@@ -1714,7 +1730,7 @@ external void get_animation_name_ffi(
ffi.Pointer<ffi.Char>,
ffi.Int,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void get_morph_target_name_ffi(
external void get_morph_target_name_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int assetEntity,
int childEntity,
@@ -1727,7 +1743,7 @@ external void get_morph_target_name_ffi(
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId, EntityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Int32)>>)>(
isLeaf: true)
external void get_morph_target_name_count_ffi(
external void get_morph_target_name_count_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
int childEntity,
@@ -1742,7 +1758,7 @@ external void get_morph_target_name_count_ffi(
ffi.Int,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Bool)>>)>(
isLeaf: true)
external void set_morph_target_weights_ffi(
external void set_morph_target_weights_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
ffi.Pointer<ffi.Float> morphData,
@@ -1754,7 +1770,7 @@ external void set_morph_target_weights_ffi(
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Bool)>>)>(
isLeaf: true)
external void update_bone_matrices_ffi(
external void update_bone_matrices_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Bool)>> callback,
@@ -1769,7 +1785,7 @@ external void update_bone_matrices_ffi(
ffi.Pointer<ffi.Float>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(ffi.Bool)>>)>(
isLeaf: true)
external void set_bone_transform_ffi(
external void set_bone_transform_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int asset,
int skinIndex,
@@ -1779,7 +1795,7 @@ external void set_bone_transform_ffi(
);
@ffi.Native<ffi.Void Function(ffi.Pointer<ffi.Void>, ffi.Bool)>(isLeaf: true)
external void set_post_processing_ffi(
external void set_post_processing_render_thread(
ffi.Pointer<ffi.Void> viewer,
bool enabled,
);
@@ -1787,7 +1803,7 @@ external void set_post_processing_ffi(
@ffi.Native<
ffi.Void Function(ffi.Pointer<ffi.Void>, EntityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void reset_to_rest_pose_ffi(
external void reset_to_rest_pose_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int entityId,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> callback,
@@ -1809,7 +1825,7 @@ external void reset_to_rest_pose_ffi(
ffi.Bool,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void create_geometry_ffi(
external void create_geometry_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
ffi.Pointer<ffi.Float> vertices,
int numVertices,
@@ -1836,7 +1852,7 @@ external void create_geometry_ffi(
ffi.Uint32,
ffi.Uint32,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
external void unproject_texture_ffi(
external void unproject_texture_render_thread(
ffi.Pointer<ffi.Void> sceneManager,
int entity,
ffi.Pointer<ffi.Uint8> input,

View File

@@ -95,7 +95,7 @@ class ThermionViewerFFI extends ThermionViewer {
Future createRenderTarget(
double width, double height, int textureHandle) async {
await withVoidCallback((callback) => create_render_target_ffi(
await withVoidCallback((callback) => create_render_target_render_thread(
_viewer!, textureHandle, width.toInt(), height.toInt(), callback));
}
@@ -123,14 +123,14 @@ class ThermionViewerFFI extends ThermionViewer {
Future createSwapChain(double width, double height,
{Pointer<Void>? surface}) async {
await withVoidCallback((callback) {
create_swap_chain_ffi(_viewer!, surface ?? nullptr, width.toInt(),
height.toInt(), callback);
create_swap_chain_render_thread(_viewer!, surface ?? nullptr,
width.toInt(), height.toInt(), callback);
});
}
Future destroySwapChain() async {
await withVoidCallback((callback) {
destroy_swap_chain_ffi(_viewer!, callback);
destroy_swap_chain_render_thread(_viewer!, callback);
});
}
@@ -143,8 +143,14 @@ class ThermionViewerFFI extends ThermionViewer {
nullptr;
var viewer = await withVoidPointerCallback(
(Pointer<NativeFunction<Void Function(Pointer<Void>)>> callback) {
create_filament_viewer_ffi(_sharedContext, _driver, uberarchivePtr,
resourceLoader, _renderCallback, _renderCallbackOwner, callback);
create_filament_viewer_render_thread(
_sharedContext,
_driver,
uberarchivePtr,
resourceLoader,
_renderCallback,
_renderCallbackOwner,
callback);
});
_viewer = Pointer.fromAddress(viewer);
allocator.free(uberarchivePtr);
@@ -178,9 +184,9 @@ class ThermionViewerFFI extends ThermionViewer {
@override
Future setRendering(bool render) async {
_rendering = render;
await withVoidCallback((cb) {
set_rendering_ffi(_viewer!, render, cb);
});
// await withVoidCallback((cb) {
// set_rendering_render_thread(_viewer!, render, cb);
// });
}
///
@@ -188,7 +194,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future render() async {
render_ffi(_viewer!);
render_render_thread(_viewer!);
}
///
@@ -201,7 +207,7 @@ class ThermionViewerFFI extends ThermionViewer {
4;
final out = allocator<Uint8>(length);
await withVoidCallback((cb) {
capture_ffi(_viewer!, out, cb);
capture_render_thread(_viewer!, out, cb);
});
final data = Uint8List.fromList(out.asTypedList(length));
allocator.free(out);
@@ -214,7 +220,7 @@ class ThermionViewerFFI extends ThermionViewer {
@override
Future setFrameRate(int framerate) async {
final interval = 1000.0 / framerate;
set_frame_interval_ffi(_viewer!, interval);
set_frame_interval_render_thread(_viewer!, interval);
}
final _onDispose = <Future Function()>[];
@@ -231,9 +237,9 @@ class ThermionViewerFFI extends ThermionViewer {
await setRendering(false);
await clearEntities();
await clearLights();
destroy_filament_viewer_ffi(_viewer!);
print("DESTROYING");
destroy_filament_viewer_render_thread(_viewer!);
print("DESTROYED");
_sceneManager = null;
_viewer = null;
await _pickResultController.close();
@@ -244,6 +250,7 @@ class ThermionViewerFFI extends ThermionViewer {
await callback.call();
}
_onDispose.clear();
print("DONE");
}
///
@@ -258,7 +265,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future clearBackgroundImage() async {
clear_background_image_ffi(_viewer!);
clear_background_image_render_thread(_viewer!);
}
///
@@ -268,7 +275,7 @@ class ThermionViewerFFI extends ThermionViewer {
Future setBackgroundImage(String path, {bool fillHeight = false}) async {
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
await withVoidCallback((cb) {
set_background_image_ffi(_viewer!, pathPtr, fillHeight, cb);
set_background_image_render_thread(_viewer!, pathPtr, fillHeight, cb);
});
allocator.free(pathPtr);
@@ -279,7 +286,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future setBackgroundColor(double r, double g, double b, double a) async {
set_background_color_ffi(_viewer!, r, g, b, a);
set_background_color_render_thread(_viewer!, r, g, b, a);
}
///
@@ -288,7 +295,7 @@ class ThermionViewerFFI extends ThermionViewer {
@override
Future setBackgroundImagePosition(double x, double y,
{bool clamp = false}) async {
set_background_image_position_ffi(_viewer!, x, y, clamp);
set_background_image_position_render_thread(_viewer!, x, y, clamp);
}
///
@@ -299,7 +306,7 @@ class ThermionViewerFFI extends ThermionViewer {
final pathPtr = skyboxPath.toNativeUtf8(allocator: allocator).cast<Char>();
await withVoidCallback((cb) {
load_skybox_ffi(_viewer!, pathPtr, cb);
load_skybox_render_thread(_viewer!, pathPtr, cb);
});
allocator.free(pathPtr);
@@ -320,7 +327,7 @@ class ThermionViewerFFI extends ThermionViewer {
Future loadIbl(String lightingPath, {double intensity = 30000}) async {
final pathPtr =
lightingPath.toNativeUtf8(allocator: allocator).cast<Char>();
load_ibl_ffi(_viewer!, pathPtr, intensity);
load_ibl_render_thread(_viewer!, pathPtr, intensity);
}
///
@@ -341,7 +348,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future removeSkybox() async {
remove_skybox_ffi(_viewer!);
remove_skybox_render_thread(_viewer!);
}
///
@@ -349,7 +356,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future removeIbl() async {
remove_ibl_ffi(_viewer!);
remove_ibl_render_thread(_viewer!);
}
@override
@@ -392,7 +399,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future<ThermionEntity> addDirectLight(DirectLight directLight) async {
var entity = await withIntCallback((callback) => add_light_ffi(
var entity = await withIntCallback((callback) => add_light_render_thread(
_viewer!,
directLight.type.index,
directLight.color,
@@ -424,7 +431,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future removeLight(ThermionEntity entity) async {
remove_light_ffi(_viewer!, entity);
remove_light_render_thread(_viewer!, entity);
_sceneUpdateEventController.add(SceneUpdateEvent.remove(entity));
}
@@ -433,7 +440,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future clearLights() async {
clear_lights_ffi(_viewer!);
clear_lights_render_thread(_viewer!);
_sceneUpdateEventController.add(SceneUpdateEvent.clearLights());
}
@@ -484,7 +491,7 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Not yet implemented");
}
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
var entity = await withIntCallback((callback) => load_glb_ffi(
var entity = await withIntCallback((callback) => load_glb_render_thread(
_sceneManager!, pathPtr, numInstances, keepData, callback));
allocator.free(pathPtr);
if (entity == _FILAMENT_ASSET_ERROR) {
@@ -515,15 +522,9 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Layer must be between 0 and 6");
}
var entity = await withIntCallback((callback) => load_glb_from_buffer_ffi(
_sceneManager!,
data.address,
data.length,
numInstances,
keepData,
priority,
layer,
callback));
var entity = await withIntCallback((callback) =>
load_glb_from_buffer_render_thread(_sceneManager!, data.address,
data.length, numInstances, keepData, priority, layer, callback));
if (entity == _FILAMENT_ASSET_ERROR) {
throw Exception("An error occurred loading GLB from buffer");
@@ -540,7 +541,7 @@ class ThermionViewerFFI extends ThermionViewer {
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
final relativeResourcePathPtr =
relativeResourcePath.toNativeUtf8(allocator: allocator).cast<Char>();
var entity = await withIntCallback((callback) => load_gltf_ffi(
var entity = await withIntCallback((callback) => load_gltf_render_thread(
_sceneManager!, pathPtr, relativeResourcePathPtr, keepData, callback));
allocator.free(pathPtr);
allocator.free(relativeResourcePathPtr);
@@ -614,7 +615,7 @@ class ThermionViewerFFI extends ThermionViewer {
weightsPtr[i] = weights[i];
}
var success = await withBoolCallback((cb) {
set_morph_target_weights_ffi(
set_morph_target_weights_render_thread(
_sceneManager!, entity, weightsPtr, weights.length, cb);
});
allocator.free(weightsPtr);
@@ -634,7 +635,7 @@ class ThermionViewerFFI extends ThermionViewer {
var names = <String>[];
var count = await withIntCallback((callback) =>
get_morph_target_name_count_ffi(
get_morph_target_name_count_render_thread(
_sceneManager!, entity, childEntity, callback));
var outPtr = allocator<Char>(255);
for (int i = 0; i < count; i++) {
@@ -944,7 +945,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
Future updateBoneMatrices(ThermionEntity entity) async {
var result = await withBoolCallback((cb) {
update_bone_matrices_ffi(_sceneManager!, entity, cb);
update_bone_matrices_render_thread(_sceneManager!, entity, cb);
});
if (!result) {
throw Exception("Failed to update bone matrices");
@@ -993,7 +994,7 @@ class ThermionViewerFFI extends ThermionViewer {
ptr[i] = transform.storage[i];
}
var result = await withBoolCallback((cb) {
set_bone_transform_ffi(
set_bone_transform_render_thread(
_sceneManager!, entity, skinIndex, boneIndex, ptr, cb);
});
@@ -1015,7 +1016,7 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("No viewer available, ignoring");
}
await withVoidCallback((cb) {
reset_to_rest_pose_ffi(_sceneManager!, entity, cb);
reset_to_rest_pose_render_thread(_sceneManager!, entity, cb);
});
}
@@ -1028,7 +1029,7 @@ class ThermionViewerFFI extends ThermionViewer {
@override
Future removeEntity(ThermionEntity entity) async {
await withVoidCallback(
(callback) => remove_entity_ffi(_viewer!, entity, callback));
(callback) => remove_entity_render_thread(_viewer!, entity, callback));
_sceneUpdateEventController.add(SceneUpdateEvent.remove(entity));
}
@@ -1041,7 +1042,7 @@ class ThermionViewerFFI extends ThermionViewer {
@override
Future clearEntities() async {
await withVoidCallback((callback) {
clear_entities_ffi(_viewer!, callback);
clear_entities_render_thread(_viewer!, callback);
});
}
@@ -1166,7 +1167,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future setToneMapping(ToneMapper mapper) async {
set_tone_mapping_ffi(_viewer!, mapper.index);
set_tone_mapping_render_thread(_viewer!, mapper.index);
}
///
@@ -1174,7 +1175,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future setPostProcessing(bool enabled) async {
set_post_processing_ffi(_viewer!, enabled);
set_post_processing_render_thread(_viewer!, enabled);
}
///
@@ -1213,7 +1214,7 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future setBloom(double bloom) async {
set_bloom_ffi(_viewer!, bloom);
set_bloom_render_thread(_viewer!, bloom);
}
///
@@ -1350,7 +1351,10 @@ class ThermionViewerFFI extends ThermionViewer {
///
///
@override
Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect,
Future setCameraLensProjection(
{double near = kNear,
double far = kFar,
double? aspect,
double focalLength = kFocalLength}) async {
aspect ??= viewportDimensions.$1 / viewportDimensions.$2;
var mainCamera = get_camera(_viewer!, get_main_camera(_viewer!));
@@ -1820,22 +1824,23 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Viewer must not be null");
}
var entity = await withIntCallback((callback) => create_geometry_ffi(
_sceneManager!,
geometry.vertices.address,
geometry.vertices.length,
geometry.normals.address,
geometry.normals.length,
geometry.uvs.address,
geometry.uvs.length,
geometry.indices.address,
geometry.indices.length,
geometry.primitiveType.index,
materialInstance == null
? nullptr
: (materialInstance as ThermionFFIMaterialInstance)._pointer,
keepData,
callback));
var entity = await withIntCallback((callback) =>
create_geometry_render_thread(
_sceneManager!,
geometry.vertices.address,
geometry.vertices.length,
geometry.normals.address,
geometry.normals.length,
geometry.uvs.address,
geometry.uvs.length,
geometry.indices.address,
geometry.indices.length,
geometry.primitiveType.index,
materialInstance == null
? nullptr
: (materialInstance as ThermionFFIMaterialInstance)._pointer,
keepData,
callback));
if (entity == _FILAMENT_ASSET_ERROR) {
throw Exception("Failed to create geometry");
}
@@ -1983,8 +1988,16 @@ class ThermionViewerFFI extends ThermionViewer {
int inputWidth, int inputHeight, int outWidth, int outHeight) async {
final outPtr = Uint8List(outWidth * outHeight * 4);
await withVoidCallback((callback) {
unproject_texture_ffi(_viewer!, entity, input.address, inputWidth,
inputHeight, outPtr.address, outWidth, outHeight, callback);
unproject_texture_render_thread(
_viewer!,
entity,
input.address,
inputWidth,
inputHeight,
outPtr.address,
outWidth,
outHeight,
callback);
});
return outPtr.buffer.asUint8List();
@@ -2132,6 +2145,11 @@ class ThermionViewerFFI extends ThermionViewer {
}
return ThermionFFIMaterialInstance(instance);
}
@override
void requestFrame() {
request_frame_render_thread(_viewer!);
}
}
class ThermionFFITexture extends ThermionTexture {

View File

@@ -58,12 +58,17 @@ abstract class ThermionViewer {
Future setRendering(bool render);
///
/// Render a single frame.
/// Render a single frame immediately.
///
Future render();
///
/// Render a single frame to the viewport and copy the pixel buffer to [out].
/// Requests a single frame to be rendered. This is only intended to be used internally.
///
void requestFrame();
///
/// Render a single frame and copy the pixel buffer to [out].
///
Future<Uint8List> capture();

View File

@@ -828,11 +828,6 @@ class ThermionViewerStub extends ThermionViewer {
throw UnimplementedError();
}
@override
Future setCameraLensProjection(double near, double far, double aspect, double focalLength) {
// TODO: implement setCameraLensProjection
throw UnimplementedError();
}
@override
Future setCameraModelMatrix4(Matrix4 matrix) {
@@ -952,6 +947,17 @@ class ThermionViewerStub extends ThermionViewer {
// TODO: implement setVisibilityLayer
throw UnimplementedError();
}
@override
void requestFrame() {
// TODO: implement requestFrame
}
@override
Future setCameraLensProjection({double near = kNear, double far = kFar, double? aspect, double focalLength = kFocalLength}) {
// TODO: implement setCameraLensProjection
throw UnimplementedError();
}
}

View File

@@ -75,7 +75,7 @@ namespace thermion_filament
void clearEntities();
void updateViewport(uint32_t width, uint32_t height);
void render(
bool render(
uint64_t frameTimeInNanos,
void *pixelBuffer,
void (*callback)(void *buf, size_t size, void *data),

View File

@@ -102,7 +102,7 @@ extern "C"
EMSCRIPTEN_KEEPALIVE EntityId get_main_camera(const void *const viewer);
EMSCRIPTEN_KEEPALIVE bool set_camera(const void *const viewer, EntityId entity, const char *nodeName);
EMSCRIPTEN_KEEPALIVE void set_view_frustum_culling(const void *const viewer, bool enabled);
EMSCRIPTEN_KEEPALIVE void render(
EMSCRIPTEN_KEEPALIVE bool render(
const void *const viewer,
uint64_t frameTimeInNanos,
void *pixelBuffer,
@@ -225,6 +225,8 @@ extern "C"
EMSCRIPTEN_KEEPALIVE void set_camera_lens_projection(TCamera *camera, double near, double far, double aspect, double focalLength);
EMSCRIPTEN_KEEPALIVE void set_camera_focus_distance(TCamera *camera, float focusDistance);
EMSCRIPTEN_KEEPALIVE void set_camera_manipulator_options(const void *const viewer, _ManipulatorMode mode, double orbitSpeedX, double orbitSpeedY, double zoomSpeed);
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* camera, double4x4 projectionMatrix, double4x4 projectionMatrixForCulling, double near, double far);
EMSCRIPTEN_KEEPALIVE int hide_mesh(void *sceneManager, EntityId entity, const char *meshName);
EMSCRIPTEN_KEEPALIVE int reveal_mesh(void *sceneManager, EntityId entity, const char *meshName);

View File

@@ -1,125 +0,0 @@
#ifndef _DART_FILAMENT_FFI_API_H
#define _DART_FILAMENT_FFI_API_H
#include "ThermionDartApi.h"
#ifdef __cplusplus
extern "C"
{
#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 create_filament_viewer_ffi(
void *const context,
void *const platform,
const char *uberArchivePath,
const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner,
void (*callback)(void *const viewer));
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_ffi(void *const viewer, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void create_render_target_ffi(void *const viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer);
EMSCRIPTEN_KEEPALIVE void render_ffi(void *const viewer);
EMSCRIPTEN_KEEPALIVE void capture_ffi(void *const viewer, uint8_t* out, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
EMSCRIPTEN_KEEPALIVE void set_rendering_ffi(void *const viewer, bool rendering, void(*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_frame_interval_ffi(void *const viewer, float frameInterval);
EMSCRIPTEN_KEEPALIVE void set_background_color_ffi(void *const viewer, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void clear_background_image_ffi(void *const viewer);
EMSCRIPTEN_KEEPALIVE void set_background_image_ffi(void *const viewer, const char *path, bool fillHeight, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_background_image_position_ffi(void *const viewer, float x, float y, bool clamp);
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_ffi(void *const viewer, int toneMapping);
EMSCRIPTEN_KEEPALIVE void set_bloom_ffi(void *const viewer, float strength);
EMSCRIPTEN_KEEPALIVE void load_skybox_ffi(void *const viewer, const char *skyboxPath, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void load_ibl_ffi(void *const viewer, const char *iblPath, float intensity);
EMSCRIPTEN_KEEPALIVE void remove_skybox_ffi(void *const viewer);
EMSCRIPTEN_KEEPALIVE void remove_ibl_ffi(void *const viewer);
EMSCRIPTEN_KEEPALIVE void add_light_ffi(
void *const viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows,
void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void remove_light_ffi(void *const viewer, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void clear_lights_ffi(void *const viewer);
EMSCRIPTEN_KEEPALIVE void load_glb_ffi(void *const sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_ffi(void *const sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void load_gltf_ffi(void *const sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void create_instance_ffi(void *const sceneManager, EntityId entityId, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void remove_entity_ffi(void *const viewer, EntityId asset, void (*callback)());
EMSCRIPTEN_KEEPALIVE void clear_entities_ffi(void *const viewer, void (*callback)());
EMSCRIPTEN_KEEPALIVE void set_camera_ffi(void *const viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void apply_weights_ffi(
void *const sceneManager,
EntityId asset,
const char *const entityName,
float *const weights,
int count);
EMSCRIPTEN_KEEPALIVE void set_animation_frame_ffi(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame);
EMSCRIPTEN_KEEPALIVE void stop_animation_ffi(void *const sceneManager, EntityId asset, int index);
EMSCRIPTEN_KEEPALIVE void get_animation_count_ffi(void *const sceneManager, EntityId asset, void (*callback)(int));
EMSCRIPTEN_KEEPALIVE void get_animation_name_ffi(void *const sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_ffi(void *const sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_ffi(void *const sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_ffi(void *const sceneManager,
EntityId asset,
const float *const morphData,
int numWeights,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_ffi(void *sceneManager,
EntityId asset, void(*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_bone_transform_ffi(
void *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_post_processing_ffi(void *const viewer, bool enabled);
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_ffi(void *const sceneManager, EntityId entityId, void(*callback)());
EMSCRIPTEN_KEEPALIVE void create_geometry_ffi(
void *const sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
bool keepData,
void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void unproject_texture_ffi(void *const sceneManager, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)());
#ifdef __cplusplus
}
#endif
#endif // _DART_FILAMENT_FFI_API_H

View File

@@ -0,0 +1,126 @@
#ifndef _DART_FILAMENT_FFI_API_H
#define _DART_FILAMENT_FFI_API_H
#include "ThermionDartApi.h"
#ifdef __cplusplus
extern "C"
{
#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 create_filament_viewer_render_thread(
void *const context,
void *const platform,
const char *uberArchivePath,
const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner,
void (*callback)(void *const viewer));
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(void *const viewer, void *const surface, uint32_t width, uint32_t height, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(void *const viewer, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(void *const viewer, intptr_t nativeTextureId, uint32_t width, uint32_t height, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void render_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void capture_render_thread(void *const viewer, uint8_t* out, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE FilamentRenderCallback make_render_callback_fn_pointer(FilamentRenderCallback);
EMSCRIPTEN_KEEPALIVE void set_rendering_render_thread(void *const viewer, bool rendering, void(*onComplete)());
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void set_frame_interval_render_thread(void *const viewer, float frameInterval);
EMSCRIPTEN_KEEPALIVE void set_background_color_render_thread(void *const viewer, const float r, const float g, const float b, const float a);
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(void *const viewer, const char *path, bool fillHeight, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(void *const viewer, float x, float y, bool clamp);
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(void *const viewer, int toneMapping);
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(void *const viewer, float strength);
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(void *const viewer, const char *skyboxPath, void (*onComplete)());
EMSCRIPTEN_KEEPALIVE void load_ibl_render_thread(void *const viewer, const char *iblPath, float intensity);
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void remove_ibl_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void add_light_render_thread(
void *const viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows,
void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void remove_light_render_thread(void *const viewer, EntityId entityId);
EMSCRIPTEN_KEEPALIVE void clear_lights_render_thread(void *const viewer);
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(void *const sceneManager, const char *assetPath, int numInstances, bool keepData, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(void *const sceneManager, const uint8_t *const data, size_t length, int numInstances, bool keepData, int priority, int layer, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void load_gltf_render_thread(void *const sceneManager, const char *assetPath, const char *relativePath, bool keepData, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void create_instance_render_thread(void *const sceneManager, EntityId entityId, void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(void *const viewer, EntityId asset, void (*callback)());
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(void *const viewer, void (*callback)());
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(void *const viewer, EntityId asset, const char *nodeName, void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void apply_weights_render_thread(
void *const sceneManager,
EntityId asset,
const char *const entityName,
float *const weights,
int count);
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(void *const sceneManager, EntityId asset, int animationIndex, int animationFrame);
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(void *const sceneManager, EntityId asset, int index);
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(void *const sceneManager, EntityId asset, void (*callback)(int));
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(void *const sceneManager, EntityId asset, char *const outPtr, int index, void (*callback)());
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_render_thread(void *const sceneManager, EntityId assetEntity, EntityId childEntity, char *const outPtr, int index, void (*callback)());
EMSCRIPTEN_KEEPALIVE void get_morph_target_name_count_render_thread(void *const sceneManager, EntityId asset, EntityId childEntity, void (*callback)(int32_t));
EMSCRIPTEN_KEEPALIVE void set_morph_target_weights_render_thread(void *const sceneManager,
EntityId asset,
const float *const morphData,
int numWeights,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(void *sceneManager,
EntityId asset, void(*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
void *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool));
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(void *const viewer, bool enabled);
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(void *const sceneManager, EntityId entityId, void(*callback)());
EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
void *const sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
bool keepData,
void (*callback)(EntityId));
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(void *const sceneManager, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)());
#ifdef __cplusplus
}
#endif
#endif // _DART_FILAMENT_FFI_API_H

View File

@@ -1106,7 +1106,7 @@ namespace thermion_filament
}
}
void FilamentViewer::render(
bool FilamentViewer::render(
uint64_t frameTimeInNanos,
void *pixelBuffer,
void (*callback)(void *buf, size_t size, void *data),
@@ -1115,7 +1115,7 @@ namespace thermion_filament
if (!_view || !_swapChain)
{
return;
return false;
}
auto now = std::chrono::high_resolution_clock::now();
@@ -1191,6 +1191,7 @@ namespace thermion_filament
#ifdef __EMSCRIPTEN__
_engine->execute();
#endif
return beginFrame;
}
class CaptureCallbackHandler : public filament::backend::CallbackHandler {

View File

@@ -338,14 +338,14 @@ extern "C"
cam->setModelMatrix(mat);
}
EMSCRIPTEN_KEEPALIVE void render(
EMSCRIPTEN_KEEPALIVE bool render(
const void *const viewer,
uint64_t frameTimeInNanos,
void *pixelBuffer,
void (*callback)(void *buf, size_t size, void *data),
void *data)
{
((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
return ((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data);
}
EMSCRIPTEN_KEEPALIVE void capture(
@@ -1057,4 +1057,8 @@ EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthWrite(TMaterialInstance* mate
EMSCRIPTEN_KEEPALIVE void MaterialInstance_setDepthCulling(TMaterialInstance* materialInstance, bool enabled) {
reinterpret_cast<MaterialInstance*>(materialInstance)->setDepthCulling(enabled);
}
EMSCRIPTEN_KEEPALIVE void Camera_setCustomProjectionWithCulling(TCamera* camera, double4x4 projectionMatrix, double4x4 projectionMatrixForCulling, double near, double far) {
reinterpret_cast<Camera*>(camera)->setCustomProjection(convert_double4x4_to_mat4(projectionMatrix), convert_double4x4_to_mat4(projectionMatrixForCulling), near, far);
}
}

View File

@@ -1,875 +0,0 @@
#ifdef __EMSCRIPTEN__
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include <emscripten/val.h>
extern "C"
{
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
}
#endif
#include "ThermionDartFFIApi.h"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "filament/LightManager.h"
#include <functional>
#include <mutex>
#include <thread>
#include <stdlib.h>
using namespace thermion_filament;
using namespace std::chrono_literals;
#include <time.h>
class RenderLoop
{
public:
explicit RenderLoop()
{
srand(time(NULL));
#ifdef __EMSCRIPTEN__
pthread_attr_t attr;
pthread_attr_init(&attr);
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
#else
t = new std::thread([this]() {
start();
});
#endif
}
~RenderLoop()
{
_stop = true;
#ifdef __EMSCRIPTEN__
pthread_join(t, NULL);
#else
t->join();
#endif
Log("Render loop killed");
}
static void mainLoop(void* arg) {
((RenderLoop*)arg)->iter();
}
static void *startHelper(void * parm) {
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_arg(&RenderLoop::mainLoop, parm, 0, true);
#else
((RenderLoop*)parm)->start();
#endif
return nullptr;
}
void start() {
while (!_stop) {
iter();
}
}
void iter() {
const auto frameStart = std::chrono::steady_clock::now();
if (_rendering) {
doRender();
}
std::unique_lock<std::mutex> lock(_access);
const auto frameEnd = frameStart + std::chrono::microseconds(_frameIntervalInMicroseconds);
while (std::chrono::steady_clock::now() < frameEnd) {
if (!_tasks.empty()) {
auto task = std::move(_tasks.front());
_tasks.pop_front();
lock.unlock();
task();
lock.lock();
} else {
_cond.wait_until(lock, frameEnd);
}
}
}
void createViewer(void *const context,
void *const platform,
const char *uberArchivePath,
const ResourceLoaderWrapper *const loader,
void (*renderCallback)(void *),
void *const owner,
void (*callback)(void *const))
{
_renderCallback = renderCallback;
_renderCallbackOwner = owner;
std::packaged_task<void()> lambda([=]() mutable
{
#ifdef __EMSCRIPTEN__
_context = thermion_dart_web_create_gl_context();
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
if(success != EMSCRIPTEN_RESULT_SUCCESS) {
std::cout << "Failed to make context current." << std::endl;
return;
}
glClearColor(0.0, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// emscripten_webgl_commit_frame();
_viewer = (FilamentViewer*) create_filament_viewer((void* const) _context, loader, platform, uberArchivePath);
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0, $1);
}, callback, _viewer);
#else
_viewer = (FilamentViewer*)create_filament_viewer(context, loader, platform, uberArchivePath);
callback(_viewer);
#endif
});
auto fut = add_task(lambda);
}
void destroyViewer(FilamentViewer* viewer)
{
std::packaged_task<void()> lambda([=]() mutable {
_rendering = false;
_viewer = nullptr;
destroy_filament_viewer(viewer);
});
auto fut = add_task(lambda);
}
void setRendering(bool rendering, void(*callback)())
{
std::packaged_task<void()> lambda(
[=]() mutable
{
this->_rendering = rendering;
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = add_task(lambda);
}
void doRender()
{
#ifdef __EMSCRIPTEN__
if(emscripten_is_webgl_context_lost(_context) == EM_TRUE) {
Log("Context lost");
auto sleepFor = std::chrono::seconds(1);
std::this_thread::sleep_for(sleepFor);
return;
}
#endif
render(_viewer, 0, nullptr, nullptr, nullptr);
if (_renderCallback)
{
_renderCallback(_renderCallbackOwner);
}
#ifdef __EMSCRIPTEN__
// emscripten_webgl_commit_frame();
#endif
}
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(_access);
auto ret = pt.get_future();
_tasks.push_back([pt = std::make_shared<std::packaged_task<Rt()>>(
std::move(pt))]
{ (*pt)(); });
_cond.notify_one();
return ret;
}
bool _stop = false;
bool _rendering = false;
int _frameIntervalInMicroseconds = 1000000.0 / 60.0;
std::mutex _access;
void (*_renderCallback)(void *const) = nullptr;
void *_renderCallbackOwner = nullptr;
std::condition_variable _cond;
std::deque<std::function<void()>> _tasks;
FilamentViewer* _viewer = nullptr;
#ifdef __EMSCRIPTEN__
pthread_t t;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
int _frameNum = 0;
#else
std::thread *t = nullptr;
#endif
};
extern "C"
{
static RenderLoop *_rl;
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_ffi(
void *const context, void *const platform, const char *uberArchivePath,
const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner,
void (*callback)(void *const))
{
if (!_rl)
{
_rl = new RenderLoop();
}
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapper *const)loader,
renderCallback, renderCallbackOwner, callback);
}
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_ffi(void *const viewer)
{
_rl->destroyViewer((FilamentViewer*)viewer);
delete _rl;
_rl = nullptr;
}
EMSCRIPTEN_KEEPALIVE void create_swap_chain_ffi(void *const viewer,
void *const surface,
uint32_t width,
uint32_t height,
void (*onComplete)())
{
std::packaged_task<void()> lambda(
[=]() mutable
{
create_swap_chain(viewer, surface, width, height);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_ffi(void *const viewer, void (*onComplete)())
{
Log("Destroying swapchain");
std::packaged_task<void()> lambda(
[=]() mutable
{
destroy_swap_chain(viewer);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void create_render_target_ffi(void *const viewer,
intptr_t nativeTextureId,
uint32_t width,
uint32_t height,
void (*onComplete)())
{
std::packaged_task<void()> lambda([=]() mutable
{
create_render_target(viewer, nativeTextureId, width, height);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_rendering_ffi(void *const viewer,
bool rendering, void (*callback)())
{
if (!_rl)
{
Log("No render loop!"); // PANIC?
}
else
{
_rl->setRendering(rendering, callback);
if (rendering)
{
Log("Set rendering to true");
}
else
{
Log("Set rendering to false");
}
}
}
EMSCRIPTEN_KEEPALIVE void
set_frame_interval_ffi(void* const 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 render_ffi(void *const viewer)
{
std::packaged_task<void()> lambda([=]() mutable
{ _rl->doRender(); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void capture_ffi(void *const viewer, uint8_t* pixelBuffer, void (*onComplete)()) {
std::packaged_task<void()> lambda([=]() mutable
{ capture(viewer, pixelBuffer, onComplete); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
set_background_color_ffi(void *const 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 load_gltf_ffi(void *const sceneManager,
const char *path,
const char *relativeResourcePath,
bool keepData,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda([=]() mutable
{
auto entity = load_gltf(sceneManager, path, relativeResourcePath, keepData);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0, $1);
}, callback, entity);
#else
callback(entity);
#endif
return entity; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_glb_ffi(void *const sceneManager,
const char *path,
int numInstances,
bool keepData,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda(
[=]() mutable
{
auto entity = load_glb(sceneManager, path, numInstances, keepData);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0, $1);
}, callback, entity);
#else
callback(entity);
#endif
return entity;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_ffi(void *const sceneManager,
const uint8_t *const data,
size_t length,
int numInstances,
bool keepData,
int priority,
int layer,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda(
[=]() mutable
{
auto entity = load_glb_from_buffer(sceneManager, data, length, keepData, priority, layer);
callback(entity);
return entity;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_background_image_ffi(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ clear_background_image(viewer); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_ffi(void *const viewer,
const char *path,
bool fillHeight, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
set_background_image(viewer, path, fillHeight);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_position_ffi(void *const viewer,
float x, float y,
bool clamp)
{
std::packaged_task<void()> lambda(
[=]
{ set_background_image_position(viewer, x, y, clamp); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_ffi(void *const viewer,
int toneMapping)
{
std::packaged_task<void()> lambda(
[=]
{ set_tone_mapping(viewer, toneMapping); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_bloom_ffi(void *const viewer, float strength)
{
std::packaged_task<void()> lambda([=]
{ set_bloom(viewer, strength); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_skybox_ffi(void *const viewer,
const char *skyboxPath,
void (*onComplete)())
{
std::packaged_task<void()> lambda([=]
{
load_skybox(viewer, skyboxPath);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_ibl_ffi(void *const viewer, const char *iblPath,
float intensity)
{
std::packaged_task<void()> lambda(
[=]
{ load_ibl(viewer, iblPath, intensity); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_skybox_ffi(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ remove_skybox(viewer); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_ibl_ffi(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ remove_ibl(viewer); });
auto fut = _rl->add_task(lambda);
}
void add_light_ffi(
void *const viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda([=]
{
auto entity = add_light(
viewer,
type,
colour,
intensity,
posX,
posY,
posZ,
dirX,
dirY,
dirZ,
falloffRadius,
spotLightConeInner,
spotLightConeOuter,
sunAngularRadius,
sunHaloSize,
sunHaloFallof,
shadows);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0, $1);
}, callback, entity);
#else
callback(entity);
#endif
return entity; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_light_ffi(void *const viewer,
EntityId entityId)
{
std::packaged_task<void()> lambda([=]
{ remove_light(viewer, entityId); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_lights_ffi(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ clear_lights(viewer); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_entity_ffi(void *const viewer,
EntityId asset, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
remove_entity(viewer, asset);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_entities_ffi(void *const viewer, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
clear_entities(viewer);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_camera_ffi(void *const viewer, EntityId asset,
const char *nodeName, void (*callback)(bool))
{
std::packaged_task<bool()> lambda(
[=]
{
auto success = set_camera(viewer, asset, nodeName);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, success);
#else
callback(success);
#endif
return success;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_ffi(void *sceneManager, EntityId assetEntity,
EntityId childEntity, char *const outPtr, int index, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_count_ffi(void *sceneManager, EntityId assetEntity,
EntityId childEntity, void (*callback)(int))
{
std::packaged_task<int()> lambda([=]
{
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, count);
#else
callback(count);
#endif
return count; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_animation_frame_ffi(void *const sceneManager,
EntityId asset,
int animationIndex,
int animationFrame)
{
std::packaged_task<void()> lambda([=]
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void stop_animation_ffi(void *const sceneManager,
EntityId asset, int index)
{
std::packaged_task<void()> lambda(
[=]
{ stop_animation(sceneManager, asset, index); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void get_animation_count_ffi(void *const sceneManager,
EntityId asset,
void (*callback)(int))
{
std::packaged_task<int()> lambda(
[=]
{
auto count = get_animation_count(sceneManager, asset);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, count);
#else
callback(count);
#endif
return count;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void get_animation_name_ffi(void *const sceneManager,
EntityId asset,
char *const outPtr,
int index,
void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
get_animation_name(sceneManager, asset, outPtr, index);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_post_processing_ffi(void *const viewer,
bool enabled)
{
std::packaged_task<void()> lambda(
[=]
{ set_post_processing(viewer, enabled); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_name_for_entity_ffi(void *const sceneManager, const EntityId entityId, void (*callback)(const char *))
{
std::packaged_task<const char *()> lambda(
[=]
{
auto name = get_name_for_entity(sceneManager, entityId);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, name);
#else
callback(name);
#endif
return name;
});
auto fut = _rl->add_task(lambda);
}
void set_morph_target_weights_ffi(void *const sceneManager,
EntityId asset,
const float *const morphData,
int numWeights,
void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]
{
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, result);
#else
callback(result);
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_bone_transform_ffi(
void *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool))
{
std::packaged_task<bool()> lambda(
[=]
{
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, success);
#else
callback(success);
#endif
return success;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_ffi(void *sceneManager,
EntityId entity, void(*callback)(bool)) {
std::packaged_task<void()> lambda(
[=]
{
auto success = update_bone_matrices(sceneManager, entity);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback, success);
#else
callback(success);
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_ffi(void *const sceneManager, EntityId entityId, void(*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
reset_to_rest_pose(sceneManager, entityId);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0);
}, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void create_geometry_ffi(
void *const sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance * materialInstance,
bool keepData,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda(
[=]
{
auto entity = create_geometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstance, keepData);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, entity);
#else
callback(entity);
#endif
return entity;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void unproject_texture_ffi(void *const viewer, EntityId entity, uint8_t* input, uint32_t inputWidth, uint32_t inputHeight, uint8_t* out, uint32_t outWidth, uint32_t outHeight, void(*callback)()) {
std::packaged_task<void()> lambda(
[=]
{
unproject_texture(viewer, entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
callback();
});
auto fut = _rl->add_task(lambda);
}
}

View File

@@ -0,0 +1,847 @@
#ifdef __EMSCRIPTEN__
#define GL_GLEXT_PROTOTYPES
#include <GL/gl.h>
#include <GL/glext.h>
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>
#include <emscripten/html5.h>
#include <emscripten/threading.h>
#include <emscripten/val.h>
extern "C"
{
extern EMSCRIPTEN_KEEPALIVE EMSCRIPTEN_WEBGL_CONTEXT_HANDLE thermion_dart_web_create_gl_context();
}
#endif
#include "ThermionDartRenderThreadApi.h"
#include "FilamentViewer.hpp"
#include "Log.hpp"
#include "ThreadPool.hpp"
#include "filament/LightManager.h"
#include <functional>
#include <mutex>
#include <thread>
#include <stdlib.h>
using namespace thermion_filament;
using namespace std::chrono_literals;
#include <time.h>
class RenderLoop
{
public:
explicit RenderLoop()
{
srand(time(NULL));
#ifdef __EMSCRIPTEN__
pthread_attr_t attr;
pthread_attr_init(&attr);
emscripten_pthread_attr_settransferredcanvases(&attr, "canvas");
pthread_create(&t, &attr, &RenderLoop::startHelper, this);
#else
t = new std::thread([this]()
{ start(); });
#endif
}
~RenderLoop()
{
_render = false;
_stop = true;
_cv.notify_one();
#ifdef __EMSCRIPTEN__
pthread_join(t, NULL);
#else
t->join();
#endif
}
static void mainLoop(void *arg)
{
((RenderLoop *)arg)->iter();
}
static void *startHelper(void *parm)
{
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop_arg(&RenderLoop::mainLoop, parm, 0, true);
#else
((RenderLoop *)parm)->start();
#endif
return nullptr;
}
void start()
{
while (!_stop)
{
iter();
}
}
void requestFrame()
{
this->_render = true;
}
void iter()
{
std::unique_lock<std::mutex> lock(_mutex);
if (_render)
{
doRender();
_render = false;
// Calculate and print FPS
auto currentTime = std::chrono::high_resolution_clock::now();
float deltaTime = std::chrono::duration<float, std::chrono::seconds::period>(currentTime - _lastFrameTime).count();
_lastFrameTime = currentTime;
_frameCount++;
_accumulatedTime += deltaTime;
if (_accumulatedTime >= 1.0f) // Update FPS every second
{
_fps = _frameCount / _accumulatedTime;
std::cout << "FPS: " << _fps << std::endl;
_frameCount = 0;
_accumulatedTime = 0.0f;
}
}
if (!_tasks.empty())
{
auto task = std::move(_tasks.front());
_tasks.pop_front();
lock.unlock();
task();
lock.lock();
}
_cv.wait_for(lock, std::chrono::microseconds(1000), [this]
{ return !_tasks.empty() || _stop || _render; });
if (_stop)
return;
}
void createViewer(void *const context,
void *const platform,
const char *uberArchivePath,
const ResourceLoaderWrapper *const loader,
void (*renderCallback)(void *),
void *const owner,
void (*callback)(void *const))
{
_renderCallback = renderCallback;
_renderCallbackOwner = owner;
std::packaged_task<void()> lambda([=]() mutable
{
#ifdef __EMSCRIPTEN__
_context = thermion_dart_web_create_gl_context();
auto success = emscripten_webgl_make_context_current((EMSCRIPTEN_WEBGL_CONTEXT_HANDLE)_context);
if (success != EMSCRIPTEN_RESULT_SUCCESS)
{
std::cout << "Failed to make context current." << std::endl;
return;
}
glClearColor(0.0, 0.5, 0.5, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
// emscripten_webgl_commit_frame();
_viewer = (FilamentViewer *)create_filament_viewer((void *const)_context, loader, platform, uberArchivePath);
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, _viewer);
#else
_viewer = (FilamentViewer *)create_filament_viewer(context, loader, platform, uberArchivePath);
callback(_viewer);
#endif
});
auto fut = add_task(lambda);
}
void destroyViewer(FilamentViewer *viewer)
{
std::packaged_task<void()> lambda([=]() mutable
{
_render = false;
_viewer = nullptr;
destroy_filament_viewer(viewer); });
auto fut = add_task(lambda);
fut.wait();
}
bool doRender()
{
#ifdef __EMSCRIPTEN__
if (emscripten_is_webgl_context_lost(_context) == EM_TRUE)
{
Log("Context lost");
auto sleepFor = std::chrono::seconds(1);
std::this_thread::sleep_for(sleepFor);
return;
}
#endif
auto rendered = render(_viewer, 0, nullptr, nullptr, nullptr);
if (_renderCallback)
{
_renderCallback(_renderCallbackOwner);
}
return rendered;
#ifdef __EMSCRIPTEN__
// emscripten_webgl_commit_frame();
#endif
}
void setFrameIntervalInMilliseconds(float frameIntervalInMilliseconds)
{
std::unique_lock<std::mutex> lock(_mutex);
_frameIntervalInMicroseconds = static_cast<int>(1000.0f * frameIntervalInMilliseconds);
}
template <class Rt>
auto add_task(std::packaged_task<Rt()> &pt) -> std::future<Rt>
{
std::unique_lock<std::mutex> lock(_mutex);
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;
}
private:
bool _stop = false;
bool _render = false;
int _frameIntervalInMicroseconds = 1000000 / 60;
std::mutex _mutex;
std::condition_variable _cv;
void (*_renderCallback)(void *const) = nullptr;
void *_renderCallbackOwner = nullptr;
std::deque<std::function<void()>> _tasks;
FilamentViewer *_viewer = nullptr;
std::chrono::high_resolution_clock::time_point _lastFrameTime;
int _frameCount = 0;
float _accumulatedTime = 0.0f;
float _fps = 0.0f;
#ifdef __EMSCRIPTEN__
pthread_t t;
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE _context;
#else
std::thread *t = nullptr;
#endif
};
extern "C"
{
static RenderLoop *_rl;
EMSCRIPTEN_KEEPALIVE void create_filament_viewer_render_thread(
void *const context, void *const platform, const char *uberArchivePath,
const void *const loader,
void (*renderCallback)(void *const renderCallbackOwner),
void *const renderCallbackOwner,
void (*callback)(void *const))
{
if (!_rl)
{
_rl = new RenderLoop();
}
_rl->createViewer(context, platform, uberArchivePath, (const ResourceLoaderWrapper *const)loader,
renderCallback, renderCallbackOwner, callback);
}
EMSCRIPTEN_KEEPALIVE void destroy_filament_viewer_render_thread(void *const viewer)
{
_rl->destroyViewer((FilamentViewer *)viewer);
delete _rl;
_rl = nullptr;
}
EMSCRIPTEN_KEEPALIVE void create_swap_chain_render_thread(void *const viewer,
void *const surface,
uint32_t width,
uint32_t height,
void (*onComplete)())
{
std::packaged_task<void()> lambda(
[=]() mutable
{
create_swap_chain(viewer, surface, width, height);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void destroy_swap_chain_render_thread(void *const viewer, void (*onComplete)())
{
std::packaged_task<void()> lambda(
[=]() mutable
{
destroy_swap_chain(viewer);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void create_render_target_render_thread(void *const viewer,
intptr_t nativeTextureId,
uint32_t width,
uint32_t height,
void (*onComplete)())
{
std::packaged_task<void()> lambda([=]() mutable
{
create_render_target(viewer, nativeTextureId, width, height);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void request_frame_render_thread(void *const viewer)
{
if (!_rl)
{
Log("No render loop!"); // PANIC?
}
else
{
_rl->requestFrame();
}
}
EMSCRIPTEN_KEEPALIVE void
set_frame_interval_render_thread(void *const 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 render_render_thread(void *const viewer)
{
std::packaged_task<void()> lambda([=]() mutable
{ _rl->doRender(); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void capture_render_thread(void *const viewer, uint8_t *pixelBuffer, void (*onComplete)())
{
std::packaged_task<void()> lambda([=]() mutable
{ capture(viewer, pixelBuffer, onComplete); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
set_background_color_render_thread(void *const 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 load_gltf_render_thread(void *const sceneManager,
const char *path,
const char *relativeResourcePath,
bool keepData,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda([=]() mutable
{
auto entity = load_gltf(sceneManager, path, relativeResourcePath, keepData);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0, $1);
}, callback, entity);
#else
callback(entity);
#endif
return entity; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_glb_render_thread(void *const sceneManager,
const char *path,
int numInstances,
bool keepData,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda(
[=]() mutable
{
auto entity = load_glb(sceneManager, path, numInstances, keepData);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, entity);
#else
callback(entity);
#endif
return entity;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_glb_from_buffer_render_thread(void *const sceneManager,
const uint8_t *const data,
size_t length,
int numInstances,
bool keepData,
int priority,
int layer,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda(
[=]() mutable
{
auto entity = load_glb_from_buffer(sceneManager, data, length, keepData, priority, layer);
callback(entity);
return entity;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_background_image_render_thread(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ clear_background_image(viewer); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_render_thread(void *const viewer,
const char *path,
bool fillHeight, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
set_background_image(viewer, path, fillHeight);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_background_image_position_render_thread(void *const viewer,
float x, float y,
bool clamp)
{
std::packaged_task<void()> lambda(
[=]
{ set_background_image_position(viewer, x, y, clamp); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_tone_mapping_render_thread(void *const viewer,
int toneMapping)
{
std::packaged_task<void()> lambda(
[=]
{ set_tone_mapping(viewer, toneMapping); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_bloom_render_thread(void *const viewer, float strength)
{
std::packaged_task<void()> lambda([=]
{ set_bloom(viewer, strength); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_skybox_render_thread(void *const viewer,
const char *skyboxPath,
void (*onComplete)())
{
std::packaged_task<void()> lambda([=]
{
load_skybox(viewer, skyboxPath);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, onComplete);
#else
onComplete();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void load_ibl_render_thread(void *const viewer, const char *iblPath,
float intensity)
{
std::packaged_task<void()> lambda(
[=]
{ load_ibl(viewer, iblPath, intensity); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_skybox_render_thread(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ remove_skybox(viewer); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_ibl_render_thread(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ remove_ibl(viewer); });
auto fut = _rl->add_task(lambda);
}
void add_light_render_thread(
void *const viewer,
uint8_t type,
float colour,
float intensity,
float posX,
float posY,
float posZ,
float dirX,
float dirY,
float dirZ,
float falloffRadius,
float spotLightConeInner,
float spotLightConeOuter,
float sunAngularRadius,
float sunHaloSize,
float sunHaloFallof,
bool shadows,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda([=]
{
auto entity = add_light(
viewer,
type,
colour,
intensity,
posX,
posY,
posZ,
dirX,
dirY,
dirZ,
falloffRadius,
spotLightConeInner,
spotLightConeOuter,
sunAngularRadius,
sunHaloSize,
sunHaloFallof,
shadows);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0, $1);
}, callback, entity);
#else
callback(entity);
#endif
return entity; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_light_render_thread(void *const viewer,
EntityId entityId)
{
std::packaged_task<void()> lambda([=]
{ remove_light(viewer, entityId); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_lights_render_thread(void *const viewer)
{
std::packaged_task<void()> lambda([=]
{ clear_lights(viewer); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void remove_entity_render_thread(void *const viewer,
EntityId asset, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
remove_entity(viewer, asset);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void clear_entities_render_thread(void *const viewer, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
clear_entities(viewer);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_camera_render_thread(void *const viewer, EntityId asset,
const char *nodeName, void (*callback)(bool))
{
std::packaged_task<bool()> lambda(
[=]
{
auto success = set_camera(viewer, asset, nodeName);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, success);
#else
callback(success);
#endif
return success;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_render_thread(void *sceneManager, EntityId assetEntity,
EntityId childEntity, char *const outPtr, int index, void (*callback)())
{
std::packaged_task<void()> lambda([=]
{
get_morph_target_name(sceneManager, assetEntity, childEntity, outPtr, index);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_morph_target_name_count_render_thread(void *sceneManager, EntityId assetEntity,
EntityId childEntity, void (*callback)(int))
{
std::packaged_task<int()> lambda([=]
{
auto count = get_morph_target_name_count(sceneManager, assetEntity, childEntity);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({
moduleArg.dartFilamentResolveCallback($0,$1);
}, callback, count);
#else
callback(count);
#endif
return count; });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_animation_frame_render_thread(void *const sceneManager,
EntityId asset,
int animationIndex,
int animationFrame)
{
std::packaged_task<void()> lambda([=]
{ set_animation_frame(sceneManager, asset, animationIndex, animationFrame); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void stop_animation_render_thread(void *const sceneManager,
EntityId asset, int index)
{
std::packaged_task<void()> lambda(
[=]
{ stop_animation(sceneManager, asset, index); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void get_animation_count_render_thread(void *const sceneManager,
EntityId asset,
void (*callback)(int))
{
std::packaged_task<int()> lambda(
[=]
{
auto count = get_animation_count(sceneManager, asset);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, count);
#else
callback(count);
#endif
return count;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void get_animation_name_render_thread(void *const sceneManager,
EntityId asset,
char *const outPtr,
int index,
void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
get_animation_name(sceneManager, asset, outPtr, index);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_post_processing_render_thread(void *const viewer,
bool enabled)
{
std::packaged_task<void()> lambda(
[=]
{ set_post_processing(viewer, enabled); });
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void
get_name_for_entity_render_thread(void *const sceneManager, const EntityId entityId, void (*callback)(const char *))
{
std::packaged_task<const char *()> lambda(
[=]
{
auto name = get_name_for_entity(sceneManager, entityId);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, name);
#else
callback(name);
#endif
return name;
});
auto fut = _rl->add_task(lambda);
}
void set_morph_target_weights_render_thread(void *const sceneManager,
EntityId asset,
const float *const morphData,
int numWeights,
void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]
{
auto result = set_morph_target_weights(sceneManager, asset, morphData, numWeights);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, result);
#else
callback(result);
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void set_bone_transform_render_thread(
void *sceneManager,
EntityId asset,
int skinIndex,
int boneIndex,
const float *const transform,
void (*callback)(bool))
{
std::packaged_task<bool()> lambda(
[=]
{
auto success = set_bone_transform(sceneManager, asset, skinIndex, boneIndex, transform);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, success);
#else
callback(success);
#endif
return success;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void update_bone_matrices_render_thread(void *sceneManager,
EntityId entity, void (*callback)(bool))
{
std::packaged_task<void()> lambda(
[=]
{
auto success = update_bone_matrices(sceneManager, entity);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback, success);
#else
callback(success);
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void reset_to_rest_pose_render_thread(void *const sceneManager, EntityId entityId, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
reset_to_rest_pose(sceneManager, entityId);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0); }, callback);
#else
callback();
#endif
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void create_geometry_render_thread(
void *const sceneManager,
float *vertices,
int numVertices,
float *normals,
int numNormals,
float *uvs,
int numUvs,
uint16_t *indices,
int numIndices,
int primitiveType,
TMaterialInstance *materialInstance,
bool keepData,
void (*callback)(EntityId))
{
std::packaged_task<EntityId()> lambda(
[=]
{
auto entity = create_geometry(sceneManager, vertices, numVertices, normals, numNormals, uvs, numUvs, indices, numIndices, primitiveType, materialInstance, keepData);
#ifdef __EMSCRIPTEN__
MAIN_THREAD_EM_ASM({ moduleArg.dartFilamentResolveCallback($0, $1); }, callback, entity);
#else
callback(entity);
#endif
return entity;
});
auto fut = _rl->add_task(lambda);
}
EMSCRIPTEN_KEEPALIVE void unproject_texture_render_thread(void *const viewer, EntityId entity, uint8_t *input, uint32_t inputWidth, uint32_t inputHeight, uint8_t *out, uint32_t outWidth, uint32_t outHeight, void (*callback)())
{
std::packaged_task<void()> lambda(
[=]
{
unproject_texture(viewer, entity, input, inputWidth, inputHeight, out, outWidth, outHeight);
callback();
});
auto fut = _rl->add_task(lambda);
}
}

View File

@@ -92,7 +92,8 @@ void main() async {
print(frustum.plane5.normal);
print(frustum.plane5.constant);
await viewer.setCameraLensProjection(near:10.0, far:1000.0, aspect:1.0, focalLength:28.0);
await viewer.setCameraLensProjection(
near: 10.0, far: 1000.0, aspect: 1.0, focalLength: 28.0);
frustum = await viewer.getCameraFrustum();
print(frustum.plane5.normal);
print(frustum.plane5.constant);
@@ -459,7 +460,7 @@ void main() async {
expect(materialInstance, isNotNull);
// with depth write enabled on both materials, cube2 renders behind the white cube
await _capture(viewer, "material_instance_depth_write_enabled");
await _capture(viewer, "material_instance_depth_write_enabled");
// if we disable depth write on cube1, then cube2 will always appear in front
// (relying on insertion order)
@@ -468,12 +469,11 @@ void main() async {
// set priority for the cube1 cube to 7 (render) last, cube1 renders in front
await viewer.setPriority(cube1, 7);
await _capture(viewer, "material_instance_depth_write_disabled_with_priority");
await _capture(
viewer, "material_instance_depth_write_disabled_with_priority");
});
});
// test('create instance from glb when keepData is true', () async {
// var model = await viewer.loadGlb("$testDir/cube.glb", keepData: true);
// await viewer.transformToUnitCube(model);
@@ -901,6 +901,16 @@ void main() async {
});
});
group("render thread", () {
test("request frame on render thread", () async {
var viewer = await createViewer();
viewer.requestFrame();
await Future.delayed(Duration(milliseconds: 20));
await viewer.dispose();
});
});
group("unproject", () {
test("unproject", () async {
final dimensions = (width: 1280, height: 768);