camera fixes for assets with large bounding boxes
This commit is contained in:
@@ -197,7 +197,7 @@ abstract class FilamentController {
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
///
|
||||
Future zoomUpdate(double z);
|
||||
Future zoomUpdate(double x, double y, double z);
|
||||
|
||||
///
|
||||
/// Called by `FilamentGestureDetector`. You probably don't want to call this yourself.
|
||||
|
||||
@@ -191,16 +191,45 @@ class FilamentControllerFFI extends FilamentController {
|
||||
_isReadyForScene.complete(true);
|
||||
}
|
||||
|
||||
///
|
||||
/// I'm not exactly sure how to resize the backing textures on all platforms.
|
||||
/// So for now, I'm sticking with the safe option when the widget is resized: destroying the swapchain, recreating the textures, and creating a new swapchain.
|
||||
///
|
||||
@override
|
||||
Future resize(int width, int height, {double scaleFactor = 1.0}) async {
|
||||
_resizing = true;
|
||||
setRendering(false);
|
||||
_lib.destroy_swap_chain(_viewer!);
|
||||
await destroyTexture();
|
||||
size = ui.Size(width * _pixelRatio, height * _pixelRatio);
|
||||
_textureId = await _channel
|
||||
.invokeMethod("resize", [size.width, size.height, scaleFactor]);
|
||||
_textureIdController.add(_textureId);
|
||||
|
||||
var textures =
|
||||
await _channel.invokeMethod("createTexture", [size.width, size.height]);
|
||||
var flutterTextureId = textures[0];
|
||||
_textureId = flutterTextureId;
|
||||
|
||||
// void* on iOS (pointer to pixel buffer), void* on Android (pointer to native window), null on Windows/macOS
|
||||
var surfaceAddress = textures[1] as int? ?? 0;
|
||||
|
||||
// null on iOS/Android, void* on MacOS (pointer to metal texture), GLuid on Windows/Linux
|
||||
var nativeTexture = textures[2] as int? ?? 0;
|
||||
|
||||
_lib.create_swap_chain_ffi(
|
||||
_viewer!,
|
||||
Pointer<Void>.fromAddress(surfaceAddress),
|
||||
size.width.toInt(),
|
||||
size.height.toInt());
|
||||
if (nativeTexture != 0) {
|
||||
assert(surfaceAddress == 0);
|
||||
print("Creating render target from native texture $nativeTexture");
|
||||
_lib.create_render_target_ffi(
|
||||
_viewer!, nativeTexture, size.width.toInt(), size.height.toInt());
|
||||
}
|
||||
|
||||
_lib.update_viewport_and_camera_projection_ffi(
|
||||
_viewer!, size.width.toInt(), size.height.toInt(), scaleFactor);
|
||||
_viewer!, size.width.toInt(), size.height.toInt(), 1.0);
|
||||
|
||||
_textureIdController.add(_textureId);
|
||||
_resizing = false;
|
||||
setRendering(true);
|
||||
}
|
||||
@@ -553,11 +582,11 @@ class FilamentControllerFFI extends FilamentController {
|
||||
}
|
||||
|
||||
@override
|
||||
Future zoomUpdate(double z) async {
|
||||
Future zoomUpdate(double x, double y, double z) async {
|
||||
if (_viewer == null || _resizing) {
|
||||
throw Exception("No viewer available, ignoring");
|
||||
}
|
||||
_lib.scroll_update(_viewer!, 0.0, 0.0, z);
|
||||
_lib.scroll_update(_viewer!, x, y, z);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -434,11 +434,11 @@ class FilamentControllerMethodChannel extends FilamentController {
|
||||
await _channel.invokeMethod("scrollBegin");
|
||||
}
|
||||
|
||||
Future zoomUpdate(double z) async {
|
||||
Future zoomUpdate(double x, double y, double z) async {
|
||||
if (_viewer == null || _resizing) {
|
||||
throw Exception("No viewer available, ignoring");
|
||||
}
|
||||
await _channel.invokeMethod("scrollUpdate", [0.0, 0.0, z]);
|
||||
await _channel.invokeMethod("scrollUpdate", [x, y, z]);
|
||||
}
|
||||
|
||||
Future zoomEnd() async {
|
||||
|
||||
@@ -38,15 +38,12 @@ class FilamentGestureDetector extends StatelessWidget {
|
||||
///
|
||||
final bool listenerEnabled;
|
||||
|
||||
final double zoomDelta;
|
||||
|
||||
const FilamentGestureDetector(
|
||||
{Key? key,
|
||||
required this.controller,
|
||||
this.child,
|
||||
this.showControlOverlay = false,
|
||||
this.listenerEnabled = true,
|
||||
this.zoomDelta = 1})
|
||||
this.listenerEnabled = true})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
|
||||
@@ -32,15 +32,12 @@ class FilamentGestureDetectorDesktop extends StatefulWidget {
|
||||
///
|
||||
final bool listenerEnabled;
|
||||
|
||||
final double zoomDelta;
|
||||
|
||||
const FilamentGestureDetectorDesktop(
|
||||
{Key? key,
|
||||
required this.controller,
|
||||
this.child,
|
||||
this.showControlOverlay = false,
|
||||
this.listenerEnabled = true,
|
||||
this.zoomDelta = 1})
|
||||
this.listenerEnabled = true})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
@@ -71,15 +68,18 @@ class _FilamentGestureDetectorDesktopState
|
||||
///
|
||||
/// Scroll-wheel on desktop, interpreted as zoom
|
||||
///
|
||||
void _zoom(PointerScrollEvent pointerSignal) {
|
||||
void _zoom(PointerScrollEvent pointerSignal) async {
|
||||
_scrollTimer?.cancel();
|
||||
widget.controller.zoomBegin();
|
||||
widget.controller.zoomUpdate(pointerSignal.scrollDelta.dy > 0
|
||||
? widget.zoomDelta
|
||||
: -widget.zoomDelta);
|
||||
_scrollTimer = Timer(const Duration(milliseconds: 100), () {
|
||||
widget.controller.zoomEnd();
|
||||
_scrollTimer = null;
|
||||
await widget.controller.zoomBegin();
|
||||
await widget.controller.zoomUpdate(
|
||||
pointerSignal.localPosition.dx,
|
||||
pointerSignal.localPosition.dy,
|
||||
pointerSignal.scrollDelta.dy > 0 ? 1 : -1);
|
||||
|
||||
// we don't want to end the zoom in the same frame, because this will destroy the camera manipulator (and cancel the zoom update).
|
||||
// here, we just defer calling [zoomEnd] for 100ms to ensure the update is propagated through.
|
||||
_scrollTimer = Timer(Duration(milliseconds: 100), () async {
|
||||
await widget.controller.zoomEnd();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -108,7 +108,8 @@ class _FilamentGestureDetectorDesktopState
|
||||
// if this is the first move event, we need to call rotateStart/panStart to set the first coordinates
|
||||
if (!_pointerMoving) {
|
||||
if (d.buttons == kTertiaryButton) {
|
||||
widget.controller.rotateStart(d.position.dx, d.position.dy);
|
||||
widget.controller
|
||||
.rotateStart(d.localPosition.dx, d.localPosition.dy);
|
||||
} else {
|
||||
widget.controller
|
||||
.panStart(d.localPosition.dx, d.localPosition.dy);
|
||||
@@ -117,7 +118,8 @@ class _FilamentGestureDetectorDesktopState
|
||||
// set the _pointerMoving flag so we don't call rotateStart/panStart on future move events
|
||||
_pointerMoving = true;
|
||||
if (d.buttons == kTertiaryButton) {
|
||||
widget.controller.rotateUpdate(d.position.dx, d.position.dy);
|
||||
widget.controller
|
||||
.rotateUpdate(d.localPosition.dx, d.localPosition.dy);
|
||||
} else {
|
||||
widget.controller.panUpdate(d.localPosition.dx, d.localPosition.dy);
|
||||
}
|
||||
|
||||
@@ -158,8 +158,8 @@ class _FilamentGestureDetectorMobileState
|
||||
},
|
||||
onScaleUpdate: (ScaleUpdateDetails d) async {
|
||||
if (d.pointerCount == 2) {
|
||||
widget.controller
|
||||
.zoomUpdate(d.horizontalScale > 1 ? 0.1 : -0.1);
|
||||
widget.controller.zoomUpdate(d.localFocalPoint.dx,
|
||||
d.localFocalPoint.dy, d.horizontalScale > 1 ? 0.1 : -0.1);
|
||||
} else if (!_scaling) {
|
||||
if (_rotateOnPointerMove) {
|
||||
widget.controller
|
||||
|
||||
Reference in New Issue
Block a user