feat: add capture() function and expose viewportDimensions on ThermionViewer (allows easier saving of captured images to PNG)

This commit is contained in:
Nick Fisher
2024-08-21 14:33:48 +08:00
parent 0153b5be22
commit 0a720fae72
10 changed files with 119 additions and 20 deletions

View File

@@ -1059,6 +1059,15 @@ external void render_ffi(
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()>>)>()
external void capture_ffi(
ffi.Pointer<ffi.Void> viewer,
ffi.Pointer<ffi.Uint8> out,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@ffi.Native<FilamentRenderCallback Function(FilamentRenderCallback)>()
external FilamentRenderCallback make_render_callback_fn_pointer(
FilamentRenderCallback arg0,

View File

@@ -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<bool> 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<Uint8List> capture();
///
/// Sets the framerate for continuous rendering when [setRendering] is enabled.
///
@@ -270,10 +282,9 @@ abstract class ThermionViewer {
{List<String>? 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 {

View File

@@ -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<Void>? _sceneManager;
Pointer<Void>? _viewer;
@@ -163,6 +162,23 @@ class ThermionViewerFFI extends ThermionViewer {
render_ffi(_viewer!);
}
///
///
///
@override
Future<Uint8List> capture() async {
final length = this.viewportDimensions.$1.toInt() *
this.viewportDimensions.$2.toInt() *
4;
final out = allocator<Uint8>(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);
}
///

View File

@@ -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<Uint8List> capture() {
// TODO: implement capture
throw UnimplementedError();
}
}