diff --git a/thermion_dart/lib/thermion_dart/compatibility/native/thermion_dart.g.dart b/thermion_dart/lib/thermion_dart/compatibility/native/thermion_dart.g.dart index 596a37e4..30b657ee 100644 --- a/thermion_dart/lib/thermion_dart/compatibility/native/thermion_dart.g.dart +++ b/thermion_dart/lib/thermion_dart/compatibility/native/thermion_dart.g.dart @@ -1059,6 +1059,15 @@ external void render_ffi( ffi.Pointer viewer, ); +@ffi.Native< + ffi.Void Function(ffi.Pointer, ffi.Pointer, + ffi.Pointer>)>() +external void capture_ffi( + ffi.Pointer viewer, + ffi.Pointer out, + ffi.Pointer> onComplete, +); + @ffi.Native() external FilamentRenderCallback make_render_callback_fn_pointer( FilamentRenderCallback arg0, diff --git a/thermion_dart/lib/thermion_dart/thermion_viewer.dart b/thermion_dart/lib/thermion_dart/thermion_viewer.dart index 1d93ba75..49370879 100644 --- a/thermion_dart/lib/thermion_dart/thermion_viewer.dart +++ b/thermion_dart/lib/thermion_dart/thermion_viewer.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'dart:typed_data'; import 'package:thermion_dart/thermion_dart/scene.dart'; import 'package:vector_math/vector_math_64.dart'; @@ -19,11 +20,11 @@ enum LightType { SPOT, } -enum ShadowType { - PCF, //!< percentage-closer filtered shadows (default) - VSM, //!< variance shadows - DPCF, //!< PCF with contact hardening simulation - PCSS, //!< PCF with soft shadows and contact hardening +enum ShadowType { + PCF, //!< percentage-closer filtered shadows (default) + VSM, //!< variance shadows + DPCF, //!< PCF with contact hardening simulation + PCSS, //!< PCF with soft shadows and contact hardening } // copied from filament/backened/DriverEnums.h @@ -57,6 +58,11 @@ abstract class ThermionViewer { Future get initialized; + /// + /// The current dimensions of the viewport (in physical pixels). + /// + late (double, double) viewportDimensions; + /// /// The result(s) of calling [pick] (see below). /// This may be a broadcast stream, so you should ensure you have subscribed to this stream before calling [pick]. @@ -79,6 +85,12 @@ abstract class ThermionViewer { /// Future render(); + + /// + /// Render a single frame to the viewport and copy the pixel buffer to [out]. + /// + Future capture(); + /// /// Sets the framerate for continuous rendering when [setRendering] is enabled. /// @@ -270,10 +282,9 @@ abstract class ThermionViewer { {List? targetMeshNames}); /// - /// Clear all current morph animations for [entity]. + /// Clear all current morph animations for [entity]. /// - Future clearMorphAnimationData( - ThermionEntity entity); + Future clearMorphAnimationData(ThermionEntity entity); /// /// Resets all bones in the given entity to their rest pose. @@ -736,7 +747,6 @@ abstract class ThermionViewer { /// Register a callback to be invoked when this viewer is disposed. /// void onDispose(Future Function() callback); - } abstract class AbstractGizmo { diff --git a/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart b/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart index a0792d36..e22157a5 100644 --- a/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart +++ b/thermion_dart/lib/thermion_dart/thermion_viewer_ffi.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:math'; +import 'dart:typed_data'; import 'package:animation_tools_dart/animation_tools_dart.dart'; import 'package:thermion_dart/thermion_dart/compatibility/compatibility.dart'; import 'package:thermion_dart/thermion_dart/entities/gizmo.dart'; @@ -24,8 +25,6 @@ class ThermionViewerFFI extends ThermionViewer { double _pixelRatio = 1.0; - late (double, double) viewportDimensions; - Pointer? _sceneManager; Pointer? _viewer; @@ -163,6 +162,23 @@ class ThermionViewerFFI extends ThermionViewer { render_ffi(_viewer!); } + /// + /// + /// + @override + Future capture() async { + final length = this.viewportDimensions.$1.toInt() * + this.viewportDimensions.$2.toInt() * + 4; + final out = allocator(length); + await withVoidCallback((cb) { + capture_ffi(_viewer!, out, cb); + }); + final data = Uint8List.fromList(out.asTypedList(length)); + allocator.free(out); + return data; + } + /// /// /// @@ -198,7 +214,6 @@ class ThermionViewerFFI extends ThermionViewer { await callback.call(); } _onDispose.clear(); - } /// @@ -602,13 +617,9 @@ class ThermionViewerFFI extends ThermionViewer { Future clearMorphAnimationData(ThermionEntity entity) async { var meshEntities = await getChildEntities(entity, true); - for(final childEntity in meshEntities) { - clear_morph_animation( - _sceneManager!, - childEntity); + for (final childEntity in meshEntities) { + clear_morph_animation(_sceneManager!, childEntity); } - - } /// @@ -982,8 +993,8 @@ class ThermionViewerFFI extends ThermionViewer { bool replaceActive = true, double crossfade = 0.0, double startOffset = 0.0}) async { - play_animation( - _sceneManager!, entity, index, loop, reverse, replaceActive, crossfade, startOffset); + play_animation(_sceneManager!, entity, index, loop, reverse, replaceActive, + crossfade, startOffset); } /// diff --git a/thermion_dart/lib/thermion_dart/thermion_viewer_stub.dart b/thermion_dart/lib/thermion_dart/thermion_viewer_stub.dart index d62f5ec9..9f09e2c0 100644 --- a/thermion_dart/lib/thermion_dart/thermion_viewer_stub.dart +++ b/thermion_dart/lib/thermion_dart/thermion_viewer_stub.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'dart:typed_data'; import 'package:thermion_dart/thermion_dart/scene.dart'; import 'package:thermion_dart/thermion_dart/thermion_viewer.dart'; @@ -750,4 +751,10 @@ class ThermionViewerStub extends ThermionViewer { // TODO: implement setSoftShadowOptions throw UnimplementedError(); } + + @override + Future capture() { + // TODO: implement capture + throw UnimplementedError(); + } } diff --git a/thermion_dart/native/include/FilamentViewer.hpp b/thermion_dart/native/include/FilamentViewer.hpp index 371d227e..11e7a140 100644 --- a/thermion_dart/native/include/FilamentViewer.hpp +++ b/thermion_dart/native/include/FilamentViewer.hpp @@ -150,6 +150,7 @@ namespace thermion_filament void setRecording(bool recording); void setRecordingOutputDirectory(const char *path); + void capture(uint8_t *out, void (*onComplete)()); void setAntiAliasing(bool msaaEnabled, bool fxaaEnabled, bool taaEnabled); void setDepthOfField(); diff --git a/thermion_dart/native/include/ThermionDartApi.h b/thermion_dart/native/include/ThermionDartApi.h index 01286c8e..4a7c4c76 100644 --- a/thermion_dart/native/include/ThermionDartApi.h +++ b/thermion_dart/native/include/ThermionDartApi.h @@ -107,6 +107,10 @@ extern "C" void *pixelBuffer, void (*callback)(void *buf, size_t size, void *data), void *data); + EMSCRIPTEN_KEEPALIVE void capture( + const void *const viewer, + uint8_t *pixelBuffer, + void (*callback)(void)); EMSCRIPTEN_KEEPALIVE void create_swap_chain(const void *const viewer, const void *const window, uint32_t width, uint32_t height); EMSCRIPTEN_KEEPALIVE void destroy_swap_chain(const void *const viewer); EMSCRIPTEN_KEEPALIVE void set_frame_interval(const void *const viewer, float interval); diff --git a/thermion_dart/native/include/ThermionDartFFIApi.h b/thermion_dart/native/include/ThermionDartFFIApi.h index 8e7bdbae..7a49cf5f 100644 --- a/thermion_dart/native/include/ThermionDartFFIApi.h +++ b/thermion_dart/native/include/ThermionDartFFIApi.h @@ -30,6 +30,7 @@ extern "C" 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); diff --git a/thermion_dart/native/src/FilamentViewer.cpp b/thermion_dart/native/src/FilamentViewer.cpp index 0fd27b50..31570388 100644 --- a/thermion_dart/native/src/FilamentViewer.cpp +++ b/thermion_dart/native/src/FilamentViewer.cpp @@ -1186,6 +1186,49 @@ namespace thermion_filament #endif } + void FilamentViewer::capture(uint8_t *out, void (*onComplete)()) { + + Viewport const &vp = _view->getViewport(); + size_t pixelBufferSize = vp.width * vp.height * 4; + auto *pixelBuffer = new uint8_t[pixelBufferSize]; + auto callback = [](void *buf, size_t size, void *data) + { + + auto frameCallbackData = (std::vector*)data; + uint8_t *out = (uint8_t *)(frameCallbackData->at(0)); + void* callbackPtr = frameCallbackData->at(1); + + void (*callback)(void) = (void (*)(void))callbackPtr; + memcpy(out, buf, size); + delete frameCallbackData; + callback(); + }; + + auto userData = new std::vector { out, (void*)onComplete } ; + + auto pbd = Texture::PixelBufferDescriptor( + pixelBuffer, pixelBufferSize, + Texture::Format::RGBA, + Texture::Type::UBYTE, nullptr, callback, userData); + _renderer->beginFrame(_swapChain, 0); + + _renderer->render(_view); + + if(_rt) { + _renderer->readPixels(_rt, 0, 0, vp.width, vp.height, std::move(pbd)); + } else { + _renderer->readPixels(0, 0, vp.width, vp.height, std::move(pbd)); + } + _renderer->endFrame(); + + #ifdef __EMSCRIPTEN__ + _engine->execute(); + emscripten_webgl_commit_frame(); + #endif + } + + + void FilamentViewer::savePng(void *buf, size_t size, int frameNumber) { // std::lock_guard lock(_recordingMutex); diff --git a/thermion_dart/native/src/ThermionDartApi.cpp b/thermion_dart/native/src/ThermionDartApi.cpp index 52d0a97f..b72d0c25 100644 --- a/thermion_dart/native/src/ThermionDartApi.cpp +++ b/thermion_dart/native/src/ThermionDartApi.cpp @@ -329,6 +329,13 @@ extern "C" ((FilamentViewer *)viewer)->render(frameTimeInNanos, pixelBuffer, callback, data); } + EMSCRIPTEN_KEEPALIVE void capture( + const void *const viewer, + uint8_t *pixelBuffer, + void (*callback)(void)) { + ((FilamentViewer *)viewer)->capture(pixelBuffer, callback); + }; + EMSCRIPTEN_KEEPALIVE void set_frame_interval( const void *const viewer, float frameInterval) diff --git a/thermion_dart/native/src/ThermionDartFFIApi.cpp b/thermion_dart/native/src/ThermionDartFFIApi.cpp index dadb0c36..d6bf72d2 100644 --- a/thermion_dart/native/src/ThermionDartFFIApi.cpp +++ b/thermion_dart/native/src/ThermionDartFFIApi.cpp @@ -373,6 +373,12 @@ extern "C" auto fut = _rl->add_task(lambda); } + EMSCRIPTEN_KEEPALIVE void capture_ffi(void *const viewer, uint8_t* pixelBuffer, void (*onComplete)()) { + std::packaged_task 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)