Skip to content

Commit

Permalink
feat: add translations into viewer
Browse files Browse the repository at this point in the history
  • Loading branch information
jvenin committed May 2, 2024
1 parent fe7894f commit 2c8afde
Show file tree
Hide file tree
Showing 5 changed files with 162 additions and 48 deletions.
8 changes: 7 additions & 1 deletion lib/classes/bouding_box.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,14 @@ class BoundingBoxModel {
required this.x,
required this.y,
required this.z,
});
}) {
_maxOfCoordinates = maxOfCoordinates;
}

late BoxCoordinate x;
late BoxCoordinate y;
late BoxCoordinate z;
double? _maxOfCoordinates;

BoundingBoxModel.zero() {
x = (min: 0, max: 1);
Expand All @@ -22,6 +25,9 @@ class BoundingBoxModel {
}

double get maxOfCoordinates {
if (_maxOfCoordinates != null) {
return _maxOfCoordinates!;
}
final xMax = math.max(x.max.abs(), x.min.abs());
final yMax = math.max(y.max.abs(), y.min.abs());
final zMax = math.max(z.max.abs(), z.min.abs());
Expand Down
11 changes: 9 additions & 2 deletions lib/classes/rotation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,15 @@ import 'package:vector_math/vector_math.dart';
class Transformation {
Transformation();

Vector3 translation = Vector3.zero();
Quaternion quaternion = Quaternion.identity();
double scaleFactor = 1;
Matrix4 matrix = Matrix4.identity();

void setTranslation(double x, double y) {
translation = Vector3(x, y, 0);
}

void setQuaternion(
double xRotation,
double yRotation,
Expand All @@ -18,7 +23,7 @@ class Transformation {
}

void composeMatrix() {
matrix = Matrix4.compose(Vector3.zero(), quaternion, Vector3.all(scaleFactor));
matrix = Matrix4.compose(translation, quaternion, Vector3.all(scaleFactor));
}

@override
Expand All @@ -28,7 +33,9 @@ class Transformation {

@override
bool operator ==(Object other) =>
other is Transformation && other.quaternion == quaternion && other.scaleFactor == scaleFactor;
other is Transformation &&
other.quaternion == quaternion &&
other.scaleFactor == scaleFactor;

@override
int get hashCode => quaternion.hashCode;
Expand Down
160 changes: 121 additions & 39 deletions lib/widgets/utils/mouse_movement_notifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,162 @@ import 'dart:math';

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:paraworld_gsf_viewer/widgets/utils/buttons.dart';
import 'package:paraworld_gsf_viewer/widgets/utils/label.dart';

typedef MousePositionDrag = ({
Offset pos,
double lastX,
double lastY,
double zoom
});

typedef MouseListener = Widget Function(
ValueNotifier<MousePositionDrag> notifier);
typedef MouseEventData = ({
MousePositionDrag mousePositionPrimary,
MousePositionDrag mousePositionSecondary,
double zoom,
});

typedef MouseListener = Widget Function(ValueNotifier<MouseEventData> notifier);

class MouseMovementNotifier extends StatelessWidget {
class MouseMovementNotifier extends StatefulWidget {
const MouseMovementNotifier({super.key, required this.mouseListener});

final MouseListener mouseListener;

@override
Widget build(BuildContext context) {
double lastX = 0;
double lastY = 0;
double refX = 0;
double refY = 0;
State<MouseMovementNotifier> createState() => _MouseMovementNotifierState();
}

class _MouseMovementNotifierState extends State<MouseMovementNotifier> {
(double, double) _lastXs = (0, 0);
(double, double) _lastYs = (0, 0);
double _refX = 0;
double _refY = 0;
bool _isPrimary = false;

final MousePositionDrag defaultPos =
(pos: const Offset(0, 0), lastX: 0, lastY: 0);
late ValueNotifier<MouseEventData> mousePosNotifier;

final mousePosNotifier = ValueNotifier<MousePositionDrag>(
(pos: const Offset(0, 0), lastX: 0, lastY: 0, zoom: 1));
@override
void initState() {
mousePosNotifier = ValueNotifier<MouseEventData>((
mousePositionPrimary: defaultPos,
mousePositionSecondary: defaultPos,
zoom: 1.0,
));
super.initState();
}

@override
Widget build(BuildContext context) {
final colorScheme = Theme.of(context).colorScheme;
return Listener(
onPointerUp: (event) {
final currentLastX = _isPrimary ? _lastXs.$1 : _lastXs.$2;
final currentLastY = _isPrimary ? _lastYs.$1 : _lastYs.$2;
final MousePositionDrag newPosData = (
pos: Offset(event.position.dx - _refX, event.position.dy - _refY),
lastX: currentLastX,
lastY: currentLastY,
);
mousePosNotifier.value = (
pos: Offset(event.position.dx - refX, event.position.dy - refY),
lastX: lastX,
lastY: lastY,
zoom: mousePosNotifier.value.zoom
mousePositionPrimary: _isPrimary
? newPosData
: mousePosNotifier.value.mousePositionPrimary,
mousePositionSecondary: _isPrimary
? mousePosNotifier.value.mousePositionSecondary
: newPosData,
zoom: mousePosNotifier.value.zoom,
);
lastX = event.position.dx - refX + lastX;
lastY = event.position.dy - refY + lastY;
final newLastX = event.position.dx - _refX + currentLastX;
final newLastY = event.position.dy - _refY + currentLastY;
_lastXs = _isPrimary ? (newLastX, _lastXs.$2) : (_lastXs.$1, newLastX);
_lastYs = _isPrimary ? (newLastY, _lastYs.$2) : (_lastYs.$1, newLastY);
},
onPointerDown: (event) {
if (event.buttons == kPrimaryMouseButton) {
refX = event.position.dx;
refY = event.position.dy;
mousePosNotifier.value = (
pos: const Offset(0, 0),
lastX: lastX,
lastY: lastY,
zoom: mousePosNotifier.value.zoom
);
}
_refX = event.position.dx;
_refY = event.position.dy;
_isPrimary = event.buttons == kPrimaryMouseButton;
final MousePositionDrag newPosData = (
pos: const Offset(0, 0),
lastX: _isPrimary ? _lastXs.$1 : _lastXs.$2,
lastY: _isPrimary ? _lastYs.$1 : _lastYs.$2,
);
mousePosNotifier.value = (
mousePositionPrimary: _isPrimary
? newPosData
: mousePosNotifier.value.mousePositionPrimary,
mousePositionSecondary: _isPrimary
? mousePosNotifier.value.mousePositionSecondary
: newPosData,
zoom: mousePosNotifier.value.zoom,
);
},
onPointerMove: (event) {
if (event.buttons == kPrimaryMouseButton) {
mousePosNotifier.value = (
pos: Offset(event.position.dx - refX, event.position.dy - refY),
lastX: lastX,
lastY: lastY,
zoom: mousePosNotifier.value.zoom
);
}
final MousePositionDrag newPosData = (
pos: Offset(event.position.dx - _refX, event.position.dy - _refY),
lastX: _isPrimary ? _lastXs.$1 : _lastXs.$2,
lastY: _isPrimary ? _lastYs.$1 : _lastYs.$2,
);
mousePosNotifier.value = (
mousePositionPrimary: _isPrimary
? newPosData
: mousePosNotifier.value.mousePositionPrimary,
mousePositionSecondary: _isPrimary
? mousePosNotifier.value.mousePositionSecondary
: newPosData,
zoom: mousePosNotifier.value.zoom,
);
},
onPointerSignal: (event) {
if (event is PointerScrollEvent) {
final delta =
event.scrollDelta.dy / MediaQuery.of(context).size.height;
mousePosNotifier.value = (
pos: mousePosNotifier.value.pos,
lastX: mousePosNotifier.value.lastX,
lastY: mousePosNotifier.value.lastY,
mousePositionPrimary: mousePosNotifier.value.mousePositionPrimary,
mousePositionSecondary:
mousePosNotifier.value.mousePositionSecondary,
zoom: delta < 0
? max(mousePosNotifier.value.zoom + delta, 1)
: mousePosNotifier.value.zoom + delta,
);
}
},
child: mouseListener(mousePosNotifier),
child: Column(
children: [
Expanded(child: widget.mouseListener(mousePosNotifier)),
Button.outlinedPrimary(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Label.regular(
"Reset transformations",
isBold: true,
color: colorScheme.onBackground,
),
Icon(
Icons.refresh,
color: colorScheme.onBackground,
)
],
),
onPressed: () {
_lastXs = (0, 0);
_lastYs = (0, 0);
_refX = 0;
_refY = 0;
mousePosNotifier.value = (
mousePositionPrimary: defaultPos,
mousePositionSecondary: defaultPos,
zoom: 1.0,
);
},
),
const Gap(8.0),
],
),
);
}
}
27 changes: 23 additions & 4 deletions lib/widgets/viewer/model_drawer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ModelDrawer extends CustomPainter {
required this.showSkeleton,
}) : super(repaint: mousePosition);

final ValueNotifier<MousePositionDrag> mousePosition;
final ValueNotifier<MouseEventData> mousePosition;
final Model model;
final ui.Image? overridingTexture;
final bool showNormals;
Expand Down Expand Up @@ -156,17 +156,29 @@ class ModelDrawer extends CustomPainter {

@override
void paint(Canvas canvas, Size size) {
final rotationMouseData = mousePosition.value.mousePositionPrimary;
final zRotationAngle =
(mousePosition.value.pos.dx + mousePosition.value.lastX) *
(rotationMouseData.pos.dx + rotationMouseData.lastX) *
2 *
math.pi /
size.width;

final xRotationAngle =
(mousePosition.value.pos.dy + mousePosition.value.lastY) *
(rotationMouseData.pos.dy + rotationMouseData.lastY) *
2 *
math.pi /
size.height;
final boxMax = model.boundingBox.maxOfCoordinates;
final translationMouseData = mousePosition.value.mousePositionSecondary;
final xTranslation =
(translationMouseData.pos.dx + translationMouseData.lastX) /
size.width *
boxMax;
final zTranslation =
-(translationMouseData.pos.dy + translationMouseData.lastY) /
size.height *
boxMax;
transformation.setTranslation(xTranslation, zTranslation);
transformation.setQuaternion(xRotationAngle, 0, zRotationAngle);
transformation.scaleFactor = mousePosition.value.zoom;
transformation.composeMatrix();
Expand All @@ -181,8 +193,15 @@ class ModelDrawer extends CustomPainter {
showNormals: showNormals,
showCloths: showCloth,
showTexture: showTexture,
showSkeleton: showSkeleton,
);
if (showSkeleton) {
model.drawSkeleton(
transformation,
size,
canvas,
meshColor,
);
}

drawAxis(size, canvas);
}
Expand Down
4 changes: 2 additions & 2 deletions lib/widgets/viewer/viewer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ class Viewer extends StatelessWidget {
}
}

typedef viewerControlBuilder = Widget Function(bool showCloth, bool showNormals,
typedef ViewerControlBuilder = Widget Function(bool showCloth, bool showNormals,
bool showTexture, bool showSkeleton, ChunkAttributes?);

class ViewerControlWrapper extends ConsumerWidget {
Expand All @@ -368,7 +368,7 @@ class ViewerControlWrapper extends ConsumerWidget {
required this.overridingAttributes,
});

final viewerControlBuilder builder;
final ViewerControlBuilder builder;
final ChunkAttributes? overridingAttributes;
@override
Widget build(BuildContext context, ref) {
Expand Down

0 comments on commit 2c8afde

Please sign in to comment.