feat: camera and resizing improvements

This commit is contained in:
Nick Fisher
2024-10-02 16:47:55 +08:00
parent d294938a2c
commit 562ecf2ee5
27 changed files with 840 additions and 613 deletions

View File

@@ -9,6 +9,10 @@ import 'implementations/free_flight_camera_delegate.dart';
class DelegateInputHandler implements InputHandler {
final ThermionViewer viewer;
Stream<List<InputType>> get gestures => _gesturesController.stream;
final _gesturesController = StreamController<List<InputType>>.broadcast();
final _logger = Logger("DelegateInputHandler");
InputHandlerDelegate? transformDelegate;
@@ -54,7 +58,7 @@ class DelegateInputHandler implements InputHandler {
factory DelegateInputHandler.fixedOrbit(ThermionViewer viewer,
{double minimumDistance = 10.0,
double? Function(Vector3)? getDistanceToTarget,
Future<double?> Function(Vector3)? getDistanceToTarget,
ThermionEntity? entity,
PickDelegate? pickDelegate}) =>
DelegateInputHandler(
@@ -105,39 +109,51 @@ class DelegateInputHandler implements InputHandler {
await transformDelegate?.queue(action, vector);
}
final keyTypes = <InputType>[];
for (final key in _pressedKeys) {
InputAction? keyAction;
InputType? keyType = null;
Vector3? vector;
switch (key) {
case PhysicalKey.W:
keyAction = _actions[InputType.KEYDOWN_W];
keyType = InputType.KEYDOWN_W;
vector = Vector3(0, 0, -1);
break;
case PhysicalKey.A:
keyAction = _actions[InputType.KEYDOWN_A];
keyType = InputType.KEYDOWN_A;
vector = Vector3(-1, 0, 0);
break;
case PhysicalKey.S:
keyAction = _actions[InputType.KEYDOWN_S];
keyType = InputType.KEYDOWN_S;
vector = Vector3(0, 0, 1);
break;
case PhysicalKey.D:
keyAction = _actions[InputType.KEYDOWN_D];
keyType = InputType.KEYDOWN_D;
vector = Vector3(1, 0, 0);
break;
}
if (keyAction != null) {
var transform = _axes[keyAction];
if (transform != null) {
vector = transform * vector;
if (keyType != null) {
keyAction = _actions[keyType];
if (keyAction != null) {
var transform = _axes[keyAction];
if (transform != null) {
vector = transform * vector;
}
transformDelegate?.queue(keyAction, vector!);
keyTypes.add(keyType);
}
transformDelegate?.queue(keyAction, vector!);
}
}
await transformDelegate?.execute();
var updates = _inputDeltas.keys.followedBy(keyTypes).toList();
if(updates.isNotEmpty) {
_gesturesController.add(updates);
}
_inputDeltas.clear();
_processing = false;
}

View File

@@ -4,12 +4,13 @@ import '../../../viewer/src/shared_types/camera.dart';
import '../../../viewer/viewer.dart';
import '../../input.dart';
import '../input_handler.dart';
import 'dart:math';
class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
final ThermionViewer viewer;
late Future<Camera> _camera;
final double minimumDistance;
double? Function(Vector3)? getDistanceToTarget;
Future<double?> Function(Vector3)? getDistanceToTarget;
Vector2 _queuedRotationDelta = Vector2.zero();
double _queuedZoomDelta = 0.0;
@@ -22,7 +23,14 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
this.getDistanceToTarget,
this.minimumDistance = 10.0,
}) {
_camera = viewer.getMainCamera();
_camera = viewer.getMainCamera().then((Camera cam) async {
var viewMatrix = makeViewMatrix(Vector3(0.0, 0, -minimumDistance),
Vector3.zero(), Vector3(0.0, 1.0, 0.0));
viewMatrix.invert();
await cam.setTransform(viewMatrix);
return cam;
});
}
void dispose() {
@@ -50,12 +58,20 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
}
}
bool _executing = false;
@override
Future<void> execute() async {
if (_queuedRotationDelta.length2 == 0.0 && _queuedZoomDelta == 0.0) {
return;
}
if (_executing) {
return;
}
_executing = true;
final view = await viewer.getViewAt(0);
final viewport = await view.getViewport();
@@ -66,15 +82,22 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
Vector3 currentPosition = modelMatrix.getTranslation();
Vector3 forward = -currentPosition.normalized();
if (forward.length == 0) {
forward = Vector3(0, 0, -1);
currentPosition = Vector3(0, 0, minimumDistance);
}
Vector3 right = _up.cross(forward).normalized();
Vector3 up = forward.cross(right);
// Calculate intersection point and depth
double radius = getDistanceToTarget?.call(currentPosition) ?? 1.0;
if (radius != 1.0) {
radius = currentPosition.length - radius;
}
Vector3 intersection = (-forward).scaled(radius);
// Calculate the point where the camera forward ray intersects with the
// surface of the target sphere
var distanceToTarget =
(await getDistanceToTarget?.call(currentPosition)) ?? 0;
Vector3 intersection =
(-forward).scaled(currentPosition.length - distanceToTarget);
final intersectionInViewSpace = viewMatrix *
Vector4(intersection.x, intersection.y, intersection.z, 1.0);
@@ -98,17 +121,45 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
var worldSpace3 = worldSpace.xyz.normalized() * currentPosition.length;
currentPosition = worldSpace3;
// Apply zoom
// Zoom
if (_queuedZoomDelta != 0.0) {
Vector3 toSurface = currentPosition - intersection;
currentPosition =
currentPosition + toSurface.scaled(_queuedZoomDelta * 0.1);
}
var distToIntersection =
(currentPosition - intersection).length - minimumDistance;
// Ensure minimum distance
if (currentPosition.length < radius + minimumDistance) {
currentPosition =
(currentPosition.normalized() * (radius + minimumDistance));
// if we somehow overshot the minimum distance, reset the camera to the minimum distance
if (distToIntersection < 0) {
currentPosition +=
(intersection.normalized().scaled(-distToIntersection * 10));
} else {
bool zoomingOut = _queuedZoomDelta > 0;
late Vector3 offset;
// when zooming, we don't always use fractions of the distance from
// the camera to the target (this is due to float precision issues at
// large distances, and also it doesn't work well for UI).
// if we're zooming out and the distance is less than 10m, we zoom out by 1 unit
if (zoomingOut) {
if (distToIntersection < 10) {
offset = intersection.normalized();
} else {
offset = intersection.normalized().scaled(distToIntersection / 10);
}
// if we're zooming in and the distance is less than 5m, zoom in by 1/2 the distance,
// otherwise 1/10 of the distance each time
} else {
if (distToIntersection < 5) {
offset = intersection.normalized().scaled(-distToIntersection / 2);
} else {
offset = intersection.normalized().scaled(-distToIntersection / 10);
}
if (offset.length > distToIntersection) {
offset = Vector3.zero();
}
}
currentPosition += offset;
}
}
// Calculate view matrix
@@ -126,5 +177,7 @@ class FixedOrbitRotateInputHandlerDelegate implements InputHandlerDelegate {
// Reset queued deltas
_queuedRotationDelta = Vector2.zero();
_queuedZoomDelta = 0.0;
_executing = false;
}
}

View File

@@ -27,11 +27,13 @@ enum PhysicalKey { W, A, S, D }
enum InputAction { TRANSLATE, ROTATE, PICK, NONE }
abstract class InputHandler {
Stream<List<InputType>> get gestures;
Future<void> onPointerHover(Vector2 localPosition, Vector2 delta);
Future<void> onPointerScroll(Vector2 localPosition, double scrollDelta);
Future<void> onPointerDown(Vector2 localPosition, bool isMiddle);
Future<void> onPointerMove(Vector2 localPosition, Vector2 delta, bool isMiddle);
Future<void> onPointerMove(
Vector2 localPosition, Vector2 delta, bool isMiddle);
Future<void> onPointerUp(bool isMiddle);
Future<void> onScaleStart();
Future<void> onScaleUpdate();

View File

@@ -4,32 +4,32 @@ import 'package:vector_math/vector_math_64.dart';
import '../../../../utils/matrix.dart';
import '../../thermion_viewer_base.dart';
import 'thermion_dart.g.dart';
import 'thermion_dart.g.dart' as g;
class FFICamera extends Camera {
final Pointer<TCamera> camera;
final Pointer<TEngine> engine;
final Pointer<g.TCamera> camera;
final Pointer<g.TEngine> engine;
late ThermionEntity _entity;
FFICamera(this.camera, this.engine) {
_entity = Camera_getEntity(camera);
_entity = g.Camera_getEntity(camera);
}
@override
Future setProjectionMatrixWithCulling(
Matrix4 projectionMatrix, double near, double far) async {
Camera_setCustomProjectionWithCulling(
g.Camera_setCustomProjectionWithCulling(
camera, matrix4ToDouble4x4(projectionMatrix), near, far);
}
Future<Matrix4> getModelMatrix() async {
return double4x4ToMatrix4(Camera_getModelMatrix(camera));
return double4x4ToMatrix4(g.Camera_getModelMatrix(camera));
}
@override
Future setTransform(Matrix4 transform) async {
var entity = Camera_getEntity(camera);
Engine_setTransform(engine, entity, matrix4ToDouble4x4(transform));
var entity = g.Camera_getEntity(camera);
g.Engine_setTransform(engine, entity, matrix4ToDouble4x4(transform));
}
@override
@@ -38,7 +38,7 @@ class FFICamera extends Camera {
double far = kFar,
double aspect = 1.0,
double focalLength = kFocalLength}) async {
Camera_setLensProjection(camera, near, far, aspect, focalLength);
g.Camera_setLensProjection(camera, near, far, aspect, focalLength);
}
@override
@@ -48,7 +48,7 @@ class FFICamera extends Camera {
@override
Future setModelMatrix(Matrix4 matrix) async {
Camera_setModelMatrix(camera, matrix4ToDouble4x4(matrix));
g.Camera_setModelMatrix(camera, matrix4ToDouble4x4(matrix));
}
@override
@@ -63,21 +63,29 @@ class FFICamera extends Camera {
@override
Future<double> getCullingFar() async {
return Camera_getCullingFar(camera);
return g.Camera_getCullingFar(camera);
}
@override
Future<double> getNear() async {
return Camera_getNear(camera);
return g.Camera_getNear(camera);
}
@override
Future<double> getFocalLength() async {
return Camera_getFocalLength(camera);
return g.Camera_getFocalLength(camera);
}
@override
Future<Matrix4> getViewMatrix() async {
return double4x4ToMatrix4(Camera_getViewMatrix(camera));
return double4x4ToMatrix4(g.Camera_getViewMatrix(camera));
}
@override
Future setProjection(Projection projection, double left, double right,
double bottom, double top, double near, double far) async {
var pType = g.Projection.values[projection.index];
g.Camera_setProjection(camera, pType, left,
right, bottom, top, near, far);
}
}

View File

@@ -1,11 +1,7 @@
import 'dart:ffi';
import 'package:thermion_dart/src/viewer/src/ffi/src/thermion_dart.g.dart';
import 'package:thermion_dart/src/viewer/src/shared_types/camera.dart';
import 'package:thermion_dart/src/viewer/src/shared_types/shared_types.dart';
import '../../shared_types/view.dart';
import '../thermion_viewer_ffi.dart';
import 'ffi_camera.dart';
import 'thermion_viewer_ffi.dart';
class FFIView extends View {
@@ -54,4 +50,20 @@ class FFIView extends View {
Future setRenderable(bool renderable, FFISwapChain swapChain) async {
Viewer_setViewRenderable(viewer, swapChain.swapChain, view, renderable);
}
@override
Future setFrustumCullingEnabled(bool enabled) async {
View_setFrustumCullingEnabled(view, enabled);
}
@override
Future setBloom(double strength) async {
View_setBloom(view, strength);
}
@override
Future setToneMapper(ToneMapper mapper) async {
final engine = await Viewer_getEngine(viewer);
View_setToneMappingRenderThread(view, engine, mapper.index);
}
}

View File

@@ -16,6 +16,16 @@ external ffi.Pointer<ffi.Void> make_resource_loader(
ffi.Pointer<ffi.Void> owner,
);
@ffi.Native<
ffi.Pointer<TViewer> Function(ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Void>,
ffi.Pointer<ffi.Void>, ffi.Pointer<ffi.Char>)>(isLeaf: true)
external ffi.Pointer<TViewer> Viewer_create(
ffi.Pointer<ffi.Void> context,
ffi.Pointer<ffi.Void> loader,
ffi.Pointer<ffi.Void> platform,
ffi.Pointer<ffi.Char> uberArchivePath,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>)>(isLeaf: true)
external void destroy_filament_viewer(
ffi.Pointer<TViewer> viewer,
@@ -197,12 +207,6 @@ external void set_background_color(
double a,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>, ffi.Float)>(isLeaf: true)
external void set_bloom(
ffi.Pointer<TViewer> viewer,
double strength,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>, ffi.Pointer<ffi.Char>)>(
isLeaf: true)
external void load_skybox(
@@ -329,18 +333,6 @@ external int load_glb(
bool keepData,
);
@ffi.Native<
EntityId Function(ffi.Pointer<TSceneManager>, ffi.Pointer<ffi.Void>,
ffi.Size, ffi.Bool, ffi.Int, ffi.Int)>(isLeaf: true)
external int load_glb_from_buffer(
ffi.Pointer<TSceneManager> sceneManager,
ffi.Pointer<ffi.Void> data,
int length,
bool keepData,
int priority,
int layer,
);
@ffi.Native<
EntityId Function(ffi.Pointer<TSceneManager>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.Char>, ffi.Bool)>(isLeaf: true)
@@ -379,12 +371,6 @@ external int get_main_camera(
ffi.Pointer<TViewer> viewer,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>, ffi.Bool)>(isLeaf: true)
external void set_view_frustum_culling(
ffi.Pointer<TViewer> viewer,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>, ffi.Float)>(isLeaf: true)
external void set_frame_interval(
ffi.Pointer<TViewer> viewer,
@@ -671,6 +657,18 @@ external ffi.Pointer<TScene> SceneManager_getScene(
ffi.Pointer<TSceneManager> tSceneManager,
);
@ffi.Native<
EntityId Function(ffi.Pointer<TSceneManager>, ffi.Pointer<ffi.Uint8>,
ffi.Size, ffi.Bool, ffi.Int, ffi.Int)>(isLeaf: true)
external int SceneManager_loadGlbFromBuffer(
ffi.Pointer<TSceneManager> sceneManager,
ffi.Pointer<ffi.Uint8> arg1,
int length,
bool keepData,
int priority,
int layer,
);
@ffi.Native<ffi.Bool Function(ffi.Pointer<TSceneManager>, EntityId)>(
isLeaf: true)
external bool update_bone_matrices(
@@ -792,161 +790,6 @@ external void set_scale(
double scale,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TCamera>, ffi.Float, ffi.Float, ffi.Float)>(isLeaf: true)
external void set_camera_exposure(
ffi.Pointer<TCamera> camera,
double aperture,
double shutterSpeed,
double sensitivity,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, double4x4)>(isLeaf: true)
external void set_camera_model_matrix(
ffi.Pointer<TCamera> camera,
double4x4 matrix,
);
@ffi.Native<ffi.Pointer<TCamera> Function(ffi.Pointer<TViewer>, EntityId)>(
isLeaf: true)
external ffi.Pointer<TCamera> get_camera(
ffi.Pointer<TViewer> viewer,
int entity,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_model_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_view_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_projection_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_culling_projection_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Pointer<ffi.Double> Function(ffi.Pointer<TCamera>)>(
isLeaf: true)
external ffi.Pointer<ffi.Double> get_camera_frustum(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<
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,
double near,
double far,
);
@ffi.Native<
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,
double aspect,
double near,
double far,
bool horizontal,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double get_camera_focal_length(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double Camera_getFocalLength(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double Camera_getNear(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double Camera_getCullingFar(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 Camera_getViewMatrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 Camera_getModelMatrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double get_camera_near(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double get_camera_culling_far(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Float Function(ffi.Pointer<TCamera>, ffi.Bool)>(isLeaf: true)
external double get_camera_fov(
ffi.Pointer<TCamera> camera,
bool horizontal,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, ffi.Float)>(isLeaf: true)
external void set_camera_focus_distance(
ffi.Pointer<TCamera> camera,
double focusDistance,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TCamera>, double4x4, ffi.Double, ffi.Double)>(isLeaf: true)
external void Camera_setCustomProjectionWithCulling(
ffi.Pointer<TCamera> camera,
double4x4 projectionMatrix,
double near,
double far,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, double4x4)>(isLeaf: true)
external void Camera_setModelMatrix(
ffi.Pointer<TCamera> camera,
double4x4 modelMatrix,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TCamera>, ffi.Double, ffi.Double, ffi.Double,
ffi.Double)>(isLeaf: true)
external void Camera_setLensProjection(
ffi.Pointer<TCamera> camera,
double near,
double far,
double aspect,
double focalLength,
);
@ffi.Native<EntityId Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external int Camera_getEntity(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Pointer<TEntityManager> Function(ffi.Pointer<TEngine>)>(
isLeaf: true)
external ffi.Pointer<TEntityManager> Engine_getEntityManager(
@@ -1350,6 +1193,119 @@ external void MaterialInstance_setParameterFloat2(
double y,
);
@ffi.Native<TViewport Function(ffi.Pointer<TView>)>(isLeaf: true)
external TViewport View_getViewport(
ffi.Pointer<TView> view,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Uint32, ffi.Uint32)>(
isLeaf: true)
external void View_updateViewport(
ffi.Pointer<TView> view,
int width,
int height,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Pointer<TRenderTarget>)>(
isLeaf: true)
external void View_setRenderTarget(
ffi.Pointer<TView> view,
ffi.Pointer<TRenderTarget> renderTarget,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setFrustumCullingEnabled(
ffi.Pointer<TView> view,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setPostProcessing(
ffi.Pointer<TView> tView,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setShadowsEnabled(
ffi.Pointer<TView> tView,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Int)>(isLeaf: true)
external void View_setShadowType(
ffi.Pointer<TView> tView,
int shadowType,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Float, ffi.Float)>(
isLeaf: true)
external void View_setSoftShadowOptions(
ffi.Pointer<TView> tView,
double penumbraScale,
double penumbraRatioScale,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Float)>(isLeaf: true)
external void View_setBloom(
ffi.Pointer<TView> tView,
double strength,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TView>, ffi.Pointer<TEngine>,
ffi.UnsignedInt)>(symbol: "View_setToneMapping", isLeaf: true)
external void _View_setToneMapping(
ffi.Pointer<TView> tView,
ffi.Pointer<TEngine> tEngine,
int toneMapping,
);
void View_setToneMapping(
ffi.Pointer<TView> tView,
ffi.Pointer<TEngine> tEngine,
ToneMapping toneMapping,
) =>
_View_setToneMapping(
tView,
tEngine,
toneMapping.value,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TView>, ffi.Bool, ffi.Bool, ffi.Bool)>(isLeaf: true)
external void View_setAntiAliasing(
ffi.Pointer<TView> tView,
bool msaa,
bool fxaa,
bool taa,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Int, ffi.Bool)>(
isLeaf: true)
external void View_setLayerEnabled(
ffi.Pointer<TView> tView,
int layer,
bool visible,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Pointer<TCamera>)>(
isLeaf: true)
external void View_setCamera(
ffi.Pointer<TView> tView,
ffi.Pointer<TCamera> tCamera,
);
@ffi.Native<ffi.Pointer<TScene> Function(ffi.Pointer<TView>)>(isLeaf: true)
external ffi.Pointer<TScene> View_getScene(
ffi.Pointer<TView> tView,
);
@ffi.Native<ffi.Pointer<TCamera> Function(ffi.Pointer<TView>)>(isLeaf: true)
external ffi.Pointer<TCamera> View_getCamera(
ffi.Pointer<TView> tView,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<ffi.Void>,
@@ -1468,6 +1424,21 @@ external void Viewer_requestFrameRenderThread(
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> onComplete,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TView>, ffi.Pointer<TEngine>, ffi.Int)>(isLeaf: true)
external void View_setToneMappingRenderThread(
ffi.Pointer<TView> tView,
ffi.Pointer<TEngine> tEngine,
int arg2,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Double)>(isLeaf: true)
external void View_setBloomRenderThread(
ffi.Pointer<TView> tView,
double bloom,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>)>(isLeaf: true)
external void destroy_filament_viewer_render_thread(
ffi.Pointer<TViewer> viewer,
@@ -1530,18 +1501,6 @@ external void set_background_image_position_render_thread(
bool clamp,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>, ffi.Int)>(isLeaf: true)
external void set_tone_mapping_render_thread(
ffi.Pointer<TViewer> viewer,
int toneMapping,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TViewer>, ffi.Float)>(isLeaf: true)
external void set_bloom_render_thread(
ffi.Pointer<TViewer> viewer,
double strength,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TViewer>, ffi.Pointer<ffi.Char>,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>>)>(isLeaf: true)
@@ -1556,6 +1515,28 @@ external void remove_skybox_render_thread(
ffi.Pointer<TViewer> viewer,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TSceneManager>,
ffi.Pointer<ffi.Uint8>,
ffi.Size,
ffi.Int,
ffi.Bool,
ffi.Int,
ffi.Int,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void SceneManager_loadGlbFromBufferRenderThread(
ffi.Pointer<TSceneManager> sceneManager,
ffi.Pointer<ffi.Uint8> data,
int length,
int numInstances,
bool keepData,
int priority,
int layer,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TSceneManager>,
@@ -1572,28 +1553,6 @@ external void load_glb_render_thread(
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TSceneManager>,
ffi.Pointer<ffi.Uint8>,
ffi.Size,
ffi.Int,
ffi.Bool,
ffi.Int,
ffi.Int,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>>)>(
isLeaf: true)
external void load_glb_from_buffer_render_thread(
ffi.Pointer<TSceneManager> sceneManager,
ffi.Pointer<ffi.Uint8> data,
int length,
int numInstances,
bool keepData,
int priority,
int layer,
ffi.Pointer<ffi.NativeFunction<ffi.Void Function(EntityId)>> callback,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TSceneManager>,
@@ -1833,118 +1792,202 @@ external void unproject_texture_render_thread(
ffi.Pointer<ffi.NativeFunction<ffi.Void Function()>> callback,
);
@ffi.Native<TViewport Function(ffi.Pointer<TView>)>(isLeaf: true)
external TViewport View_getViewport(
ffi.Pointer<TView> view,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Uint32, ffi.Uint32)>(
isLeaf: true)
external void View_updateViewport(
ffi.Pointer<TView> view,
int width,
int height,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Pointer<TRenderTarget>)>(
isLeaf: true)
external void View_setRenderTarget(
ffi.Pointer<TView> view,
ffi.Pointer<TRenderTarget> renderTarget,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setFrustumCullingEnabled(
ffi.Pointer<TView> view,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setPostProcessing(
ffi.Pointer<TView> tView,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Bool)>(isLeaf: true)
external void View_setShadowsEnabled(
ffi.Pointer<TView> tView,
bool enabled,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Int)>(isLeaf: true)
external void View_setShadowType(
ffi.Pointer<TView> tView,
int shadowType,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Float, ffi.Float)>(
isLeaf: true)
external void View_setSoftShadowOptions(
ffi.Pointer<TView> tView,
double penumbraScale,
double penumbraRatioScale,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Float)>(isLeaf: true)
external void View_setBloom(
ffi.Pointer<TView> tView,
double strength,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TView>, ffi.Pointer<TEngine>,
ffi.UnsignedInt)>(symbol: "View_setToneMapping", isLeaf: true)
external void _View_setToneMapping(
ffi.Pointer<TView> tView,
ffi.Pointer<TEngine> tEngine,
int toneMapping,
ffi.Void Function(
ffi.Pointer<TCamera>, ffi.Float, ffi.Float, ffi.Float)>(isLeaf: true)
external void set_camera_exposure(
ffi.Pointer<TCamera> camera,
double aperture,
double shutterSpeed,
double sensitivity,
);
void View_setToneMapping(
ffi.Pointer<TView> tView,
ffi.Pointer<TEngine> tEngine,
ToneMapping toneMapping,
) =>
_View_setToneMapping(
tView,
tEngine,
toneMapping.value,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, double4x4)>(isLeaf: true)
external void set_camera_model_matrix(
ffi.Pointer<TCamera> camera,
double4x4 matrix,
);
@ffi.Native<ffi.Pointer<TCamera> Function(ffi.Pointer<TViewer>, EntityId)>(
isLeaf: true)
external ffi.Pointer<TCamera> get_camera(
ffi.Pointer<TViewer> viewer,
int entity,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_model_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_view_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_projection_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 get_camera_culling_projection_matrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Pointer<ffi.Double> Function(ffi.Pointer<TCamera>)>(
isLeaf: true)
external ffi.Pointer<ffi.Double> get_camera_frustum(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TView>, ffi.Bool, ffi.Bool, ffi.Bool)>(isLeaf: true)
external void View_setAntiAliasing(
ffi.Pointer<TView> tView,
bool msaa,
bool fxaa,
bool taa,
ffi.Pointer<TCamera>, double4x4, ffi.Double, ffi.Double)>(isLeaf: true)
external void set_camera_projection_matrix(
ffi.Pointer<TCamera> camera,
double4x4 matrix,
double near,
double far,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Int, ffi.Bool)>(
isLeaf: true)
external void View_setLayerEnabled(
ffi.Pointer<TView> tView,
int layer,
bool visible,
@ffi.Native<
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,
double aspect,
double near,
double far,
bool horizontal,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TView>, ffi.Pointer<TCamera>)>(
isLeaf: true)
external void View_setCamera(
ffi.Pointer<TView> tView,
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double get_camera_focal_length(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double Camera_getFocalLength(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double Camera_getNear(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double Camera_getCullingFar(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 Camera_getViewMatrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double4x4 Camera_getModelMatrix(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double get_camera_near(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external double get_camera_culling_far(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<ffi.Float Function(ffi.Pointer<TCamera>, ffi.Bool)>(isLeaf: true)
external double get_camera_fov(
ffi.Pointer<TCamera> camera,
bool horizontal,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, ffi.Float)>(isLeaf: true)
external void set_camera_focus_distance(
ffi.Pointer<TCamera> camera,
double focusDistance,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TCamera>, double4x4, ffi.Double, ffi.Double)>(isLeaf: true)
external void Camera_setCustomProjectionWithCulling(
ffi.Pointer<TCamera> camera,
double4x4 projectionMatrix,
double near,
double far,
);
@ffi.Native<ffi.Void Function(ffi.Pointer<TCamera>, double4x4)>(isLeaf: true)
external void Camera_setModelMatrix(
ffi.Pointer<TCamera> camera,
double4x4 modelMatrix,
);
@ffi.Native<
ffi.Void Function(ffi.Pointer<TCamera>, ffi.Double, ffi.Double, ffi.Double,
ffi.Double)>(isLeaf: true)
external void Camera_setLensProjection(
ffi.Pointer<TCamera> camera,
double near,
double far,
double aspect,
double focalLength,
);
@ffi.Native<EntityId Function(ffi.Pointer<TCamera>)>(isLeaf: true)
external int Camera_getEntity(
ffi.Pointer<TCamera> camera,
);
@ffi.Native<
ffi.Void Function(
ffi.Pointer<TCamera>,
ffi.UnsignedInt,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double,
ffi.Double)>(symbol: "Camera_setProjection", isLeaf: true)
external void _Camera_setProjection(
ffi.Pointer<TCamera> tCamera,
int projection,
double left,
double right,
double bottom,
double top,
double near,
double far,
);
@ffi.Native<ffi.Pointer<TScene> Function(ffi.Pointer<TView>)>(isLeaf: true)
external ffi.Pointer<TScene> View_getScene(
ffi.Pointer<TView> tView,
);
@ffi.Native<ffi.Pointer<TCamera> Function(ffi.Pointer<TView>)>(isLeaf: true)
external ffi.Pointer<TCamera> View_getCamera(
ffi.Pointer<TView> tView,
);
void Camera_setProjection(
ffi.Pointer<TCamera> tCamera,
Projection projection,
double left,
double right,
double bottom,
double top,
double near,
double far,
) =>
_Camera_setProjection(
tCamera,
projection.value,
left,
right,
bottom,
top,
near,
far,
);
@ffi.Native<
ffi.Pointer<TGizmo> Function(ffi.Pointer<TEngine>, ffi.Pointer<TView>,
@@ -2218,12 +2261,6 @@ typedef DartLoadFilamentResourceIntoOutPointerFunction = void Function(
/// - setting up a render loop
typedef EntityId = ffi.Int32;
typedef DartEntityId = int;
typedef FilamentRenderCallback
= ffi.Pointer<ffi.NativeFunction<FilamentRenderCallbackFunction>>;
typedef FilamentRenderCallbackFunction = ffi.Void Function(
ffi.Pointer<ffi.Void> owner);
typedef DartFilamentRenderCallbackFunction = void Function(
ffi.Pointer<ffi.Void> owner);
final class TViewport extends ffi.Struct {
@ffi.Int32()
@@ -2255,6 +2292,27 @@ enum ToneMapping {
};
}
typedef FilamentRenderCallback
= ffi.Pointer<ffi.NativeFunction<FilamentRenderCallbackFunction>>;
typedef FilamentRenderCallbackFunction = ffi.Void Function(
ffi.Pointer<ffi.Void> owner);
typedef DartFilamentRenderCallbackFunction = void Function(
ffi.Pointer<ffi.Void> owner);
enum Projection {
Perspective(0),
Orthographic(1);
final int value;
const Projection(this.value);
static Projection fromValue(int value) => switch (value) {
0 => Perspective,
1 => Orthographic,
_ => throw ArgumentError("Unknown value for Projection: $value"),
};
}
typedef GizmoPickCallback
= ffi.Pointer<ffi.NativeFunction<GizmoPickCallbackFunction>>;
typedef GizmoPickCallbackFunction = ffi.Void Function(

View File

@@ -13,7 +13,7 @@ import '../../thermion_viewer_base.dart';
import 'package:logging/logging.dart';
import 'callbacks.dart';
import 'camera_ffi.dart';
import 'ffi_camera.dart';
import 'ffi_view.dart';
// ignore: constant_identifier_names
@@ -180,14 +180,8 @@ class ThermionViewerFFI extends ThermionViewer {
nullptr;
_viewer = await withPointerCallback(
(Pointer<NativeFunction<Void Function(Pointer<TViewer>)>> callback) {
Viewer_createOnRenderThread(
_sharedContext,
_driver,
uberarchivePtr,
resourceLoader,
_renderCallback,
_renderCallbackOwner,
callback);
Viewer_createOnRenderThread(_sharedContext, _driver, uberarchivePtr,
resourceLoader, _renderCallback, _renderCallbackOwner, callback);
});
allocator.free(uberarchivePtr);
@@ -529,8 +523,9 @@ class ThermionViewerFFI extends ThermionViewer {
throw Exception("Not yet implemented");
}
final pathPtr = path.toNativeUtf8(allocator: allocator).cast<Char>();
var entity = await withIntCallback((callback) => load_glb_render_thread(
_sceneManager!, pathPtr, numInstances, keepData, callback));
var entity = await withIntCallback((callback)=> load_glb_render_thread(
_sceneManager!, pathPtr, numInstances, keepData, callback));
allocator.free(pathPtr);
if (entity == _FILAMENT_ASSET_ERROR) {
throw Exception("An error occurred loading the asset at $path");
@@ -561,7 +556,7 @@ class ThermionViewerFFI extends ThermionViewer {
}
var entity = await withIntCallback((callback) =>
load_glb_from_buffer_render_thread(_sceneManager!, data.address,
SceneManager_loadGlbFromBufferRenderThread(_sceneManager!, data.address,
data.length, numInstances, keepData, priority, layer, callback));
if (entity == _FILAMENT_ASSET_ERROR) {
@@ -1160,7 +1155,8 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future setToneMapping(ToneMapper mapper) async {
set_tone_mapping_render_thread(_viewer!, mapper.index);
final view = await getViewAt(0);
view.setToneMapper(mapper);
}
///
@@ -1302,7 +1298,8 @@ class ThermionViewerFFI extends ThermionViewer {
///
@override
Future setViewFrustumCulling(bool enabled) async {
set_view_frustum_culling(_viewer!, enabled);
var view = await getViewAt(0);
view.setFrustumCullingEnabled(enabled);
}
///
@@ -2052,10 +2049,13 @@ class ThermionViewerFFI extends ThermionViewer {
completer.complete(true);
});
Viewer_requestFrameRenderThread(
_viewer!, callback.nativeFunction);
Viewer_requestFrameRenderThread(_viewer!, callback.nativeFunction);
await completer.future.timeout(Duration(seconds: 1));
try {
await completer.future.timeout(Duration(seconds: 1));
} catch (err) {
print("WARNING - render call timed out");
}
}
Future<Camera> createCamera() async {

View File

@@ -1,4 +1,3 @@
library;
export 'src/thermion_viewer_ffi.dart' show ThermionViewerFFI;
export 'src/camera_ffi.dart';

View File

@@ -2,7 +2,11 @@ import 'package:vector_math/vector_math_64.dart';
import '../thermion_viewer_base.dart';
enum Projection { Perspective, Orthographic }
abstract class Camera {
Future setProjection(Projection projection, double left, double right,
double bottom, double top, double near, double far);
Future setProjectionMatrixWithCulling(
Matrix4 projectionMatrix, double near, double far);

View File

@@ -1,6 +1,11 @@
import 'package:thermion_dart/thermion_dart.dart';
import 'swap_chain.dart';
///
/// The viewport currently attached to a [View].
///
/// The dimensions here are guaranteed to be in physical pixels.
///
class Viewport {
final int left;
final int bottom;
@@ -19,4 +24,7 @@ abstract class View {
Future setPostProcessing(bool enabled);
Future setAntiAliasing(bool msaa, bool fxaa, bool taa);
Future setRenderable(bool renderable, covariant SwapChain swapChain);
Future setFrustumCullingEnabled(bool enabled);
Future setToneMapper(ToneMapper mapper);
Future setBloom(double strength);
}

View File

@@ -887,7 +887,7 @@ abstract class ThermionViewer {
///
///
///
Future getActiveCamera();
Future<Camera> getActiveCamera();
///
///