more camera work
This commit is contained in:
@@ -69,11 +69,11 @@ class DelegateInputHandler implements InputHandler {
|
|||||||
});
|
});
|
||||||
|
|
||||||
factory DelegateInputHandler.flight(ThermionViewer viewer,
|
factory DelegateInputHandler.flight(ThermionViewer viewer,
|
||||||
{PickDelegate? pickDelegate, bool freeLook=false}) =>
|
{PickDelegate? pickDelegate, bool freeLook=false, double? clampY, ThermionEntity? entity}) =>
|
||||||
DelegateInputHandler(
|
DelegateInputHandler(
|
||||||
viewer: viewer,
|
viewer: viewer,
|
||||||
pickDelegate: pickDelegate,
|
pickDelegate: pickDelegate,
|
||||||
transformDelegate: FreeFlightInputHandlerDelegate(viewer),
|
transformDelegate: FreeFlightInputHandlerDelegate(viewer, clampY:clampY, entity:entity),
|
||||||
actions: {
|
actions: {
|
||||||
InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE,
|
InputType.MMB_HOLD_AND_MOVE: InputAction.ROTATE,
|
||||||
InputType.SCROLLWHEEL: InputAction.TRANSLATE,
|
InputType.SCROLLWHEEL: InputAction.TRANSLATE,
|
||||||
|
|||||||
@@ -5,14 +5,15 @@ import '../delegates.dart';
|
|||||||
import '../input_handler.dart';
|
import '../input_handler.dart';
|
||||||
|
|
||||||
class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
||||||
|
|
||||||
final ThermionViewer viewer;
|
final ThermionViewer viewer;
|
||||||
|
late Future<ThermionEntity> entity;
|
||||||
final Vector3? minBounds;
|
final Vector3? minBounds;
|
||||||
final Vector3? maxBounds;
|
final Vector3? maxBounds;
|
||||||
final double rotationSensitivity;
|
final double rotationSensitivity;
|
||||||
final double movementSensitivity;
|
final double movementSensitivity;
|
||||||
final double zoomSensitivity;
|
final double zoomSensitivity;
|
||||||
final double panSensitivity;
|
final double panSensitivity;
|
||||||
|
final double? clampY;
|
||||||
|
|
||||||
static final _up = Vector3(0, 1, 0);
|
static final _up = Vector3(0, 1, 0);
|
||||||
static final _forward = Vector3(0, 0, -1);
|
static final _forward = Vector3(0, 0, -1);
|
||||||
@@ -23,15 +24,21 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
|||||||
double _queuedZoomDelta = 0.0;
|
double _queuedZoomDelta = 0.0;
|
||||||
Vector3 _queuedMoveDelta = Vector3.zero();
|
Vector3 _queuedMoveDelta = Vector3.zero();
|
||||||
|
|
||||||
FreeFlightInputHandlerDelegate(
|
FreeFlightInputHandlerDelegate(this.viewer,
|
||||||
this.viewer, {
|
{this.minBounds,
|
||||||
this.minBounds,
|
this.maxBounds,
|
||||||
this.maxBounds,
|
this.rotationSensitivity = 0.001,
|
||||||
this.rotationSensitivity = 0.001,
|
this.movementSensitivity = 0.1,
|
||||||
this.movementSensitivity = 0.1,
|
this.zoomSensitivity = 0.1,
|
||||||
this.zoomSensitivity = 0.1,
|
this.panSensitivity = 0.1,
|
||||||
this.panSensitivity = 0.1,
|
this.clampY,
|
||||||
});
|
ThermionEntity? entity}) {
|
||||||
|
if (entity != null) {
|
||||||
|
this.entity = Future.value(entity);
|
||||||
|
} else {
|
||||||
|
this.entity = viewer.getMainCameraEntity();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> queue(InputAction action, Vector3? delta) async {
|
Future<void> queue(InputAction action, Vector3? delta) async {
|
||||||
@@ -73,10 +80,14 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4 currentModelMatrix = await viewer.getCameraModelMatrix();
|
final activeCamera = await viewer.getActiveCamera();
|
||||||
Vector3 currentPosition = currentModelMatrix.getTranslation();
|
Matrix4 currentViewMatrix = activeCamera.getViewMatrix();
|
||||||
|
|
||||||
|
|
||||||
|
Matrix4 currentTransform = await viewer.getLocalTransform(await entity);
|
||||||
|
Vector3 currentPosition = currentTransform.getTranslation();
|
||||||
Quaternion currentRotation =
|
Quaternion currentRotation =
|
||||||
Quaternion.fromRotation(currentModelMatrix.getRotation());
|
Quaternion.fromRotation(currentTransform.getRotation());
|
||||||
|
|
||||||
// Apply rotation
|
// Apply rotation
|
||||||
if (_queuedRotationDelta.length2 > 0.0) {
|
if (_queuedRotationDelta.length2 > 0.0) {
|
||||||
@@ -135,7 +146,7 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
|||||||
// Update camera
|
// Update camera
|
||||||
Matrix4 newModelMatrix =
|
Matrix4 newModelMatrix =
|
||||||
Matrix4.compose(currentPosition, currentRotation, Vector3(1, 1, 1));
|
Matrix4.compose(currentPosition, currentRotation, Vector3(1, 1, 1));
|
||||||
await viewer.setCameraModelMatrix4(newModelMatrix);
|
await viewer.setTransform(await entity, newModelMatrix);
|
||||||
|
|
||||||
_executing = false;
|
_executing = false;
|
||||||
}
|
}
|
||||||
@@ -151,6 +162,10 @@ class FreeFlightInputHandlerDelegate implements InputHandlerDelegate {
|
|||||||
position.y = position.y.clamp(double.negativeInfinity, maxBounds!.y);
|
position.y = position.y.clamp(double.negativeInfinity, maxBounds!.y);
|
||||||
position.z = position.z.clamp(double.negativeInfinity, maxBounds!.z);
|
position.z = position.z.clamp(double.negativeInfinity, maxBounds!.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clampY != null) {
|
||||||
|
position.y = clampY!;
|
||||||
|
}
|
||||||
return position;
|
return position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import '../../thermion_viewer_base.dart';
|
|||||||
import 'thermion_dart.g.dart';
|
import 'thermion_dart.g.dart';
|
||||||
|
|
||||||
class ThermionFFICamera extends Camera {
|
class ThermionFFICamera extends Camera {
|
||||||
|
|
||||||
final Pointer<TCamera> camera;
|
final Pointer<TCamera> camera;
|
||||||
final Pointer<TEngine> engine;
|
final Pointer<TEngine> engine;
|
||||||
late ThermionEntity _entity;
|
late ThermionEntity _entity;
|
||||||
@@ -52,7 +51,7 @@ class ThermionFFICamera extends Camera {
|
|||||||
Camera_setModelMatrix(camera, matrix4ToDouble4x4(matrix));
|
Camera_setModelMatrix(camera, matrix4ToDouble4x4(matrix));
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) =>
|
bool operator ==(Object other) =>
|
||||||
identical(this, other) ||
|
identical(this, other) ||
|
||||||
other is ThermionFFICamera &&
|
other is ThermionFFICamera &&
|
||||||
@@ -61,4 +60,19 @@ class ThermionFFICamera extends Camera {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => camera.hashCode;
|
int get hashCode => camera.hashCode;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getCullingFar() async {
|
||||||
|
return Camera_getCullingFar(camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getNear() async {
|
||||||
|
return Camera_getNear(camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<double> getFocalLength() async {
|
||||||
|
return Camera_getFocalLength(camera);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -819,11 +819,6 @@ external ffi.Pointer<TCamera> get_camera(
|
|||||||
int entity,
|
int entity,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
|
|
||||||
external double get_camera_focal_length(
|
|
||||||
ffi.Pointer<TCamera> camera,
|
|
||||||
);
|
|
||||||
|
|
||||||
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
|
@ffi.Native<double4x4 Function(ffi.Pointer<TCamera>)>(isLeaf: true)
|
||||||
external double4x4 get_camera_model_matrix(
|
external double4x4 get_camera_model_matrix(
|
||||||
ffi.Pointer<TCamera> camera,
|
ffi.Pointer<TCamera> camera,
|
||||||
@@ -872,6 +867,26 @@ external void set_camera_projection_from_fov(
|
|||||||
bool horizontal,
|
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<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
|
@ffi.Native<ffi.Double Function(ffi.Pointer<TCamera>)>(isLeaf: true)
|
||||||
external double get_camera_near(
|
external double get_camera_near(
|
||||||
ffi.Pointer<TCamera> camera,
|
ffi.Pointer<TCamera> camera,
|
||||||
@@ -983,6 +998,12 @@ external ffi.Pointer<TCamera> SceneManager_getCameraAt(
|
|||||||
int index,
|
int index,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ffi.Native<ffi.Pointer<TCamera> Function(ffi.Pointer<TSceneManager>)>(
|
||||||
|
isLeaf: true)
|
||||||
|
external ffi.Pointer<TCamera> SceneManager_getActiveCamera(
|
||||||
|
ffi.Pointer<TSceneManager> sceneManager,
|
||||||
|
);
|
||||||
|
|
||||||
@ffi.Native<
|
@ffi.Native<
|
||||||
ffi.Int Function(ffi.Pointer<TSceneManager>, EntityId,
|
ffi.Int Function(ffi.Pointer<TSceneManager>, EntityId,
|
||||||
ffi.Pointer<ffi.Char>)>(isLeaf: true)
|
ffi.Pointer<ffi.Char>)>(isLeaf: true)
|
||||||
|
|||||||
@@ -105,22 +105,28 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
Future updateViewportAndCameraProjection(double width, double height) async {
|
Future updateViewportAndCameraProjection(double width, double height) async {
|
||||||
viewportDimensions = (width * pixelRatio, height * pixelRatio);
|
viewportDimensions = (width * pixelRatio, height * pixelRatio);
|
||||||
update_viewport(_viewer!, width.toInt(), height.toInt());
|
update_viewport(_viewer!, width.toInt(), height.toInt());
|
||||||
var mainCamera = await getMainCamera() as ThermionFFICamera;
|
|
||||||
var near = await getCameraCullingNear();
|
|
||||||
if (near.abs() < 0.000001) {
|
|
||||||
near = kNear;
|
|
||||||
}
|
|
||||||
var far = await getCameraCullingFar();
|
|
||||||
if (far.abs() < 0.000001) {
|
|
||||||
far = kFar;
|
|
||||||
}
|
|
||||||
|
|
||||||
var aspect = viewportDimensions.$1 / viewportDimensions.$2;
|
final cameraCount = await getCameraCount();
|
||||||
var focalLength = get_camera_focal_length(mainCamera.camera);
|
|
||||||
if (focalLength.abs() < 0.1) {
|
for (int i = 0; i < cameraCount; i++) {
|
||||||
focalLength = kFocalLength;
|
var camera = await getCameraAt(i);
|
||||||
|
var near = await camera.getNear();
|
||||||
|
if (near.abs() < 0.000001) {
|
||||||
|
near = kNear;
|
||||||
|
}
|
||||||
|
var far = await camera.getCullingFar();
|
||||||
|
if (far.abs() < 0.000001) {
|
||||||
|
far = kFar;
|
||||||
|
}
|
||||||
|
|
||||||
|
var aspect = viewportDimensions.$1 / viewportDimensions.$2;
|
||||||
|
var focalLength = await camera.getFocalLength();
|
||||||
|
if (focalLength.abs() < 0.1) {
|
||||||
|
focalLength = kFocalLength;
|
||||||
|
}
|
||||||
|
camera.setLensProjection(
|
||||||
|
near: near, far: far, aspect: aspect, focalLength: focalLength);
|
||||||
}
|
}
|
||||||
Camera_setLensProjection(mainCamera.camera, near, far, aspect, focalLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future createSwapChain(double width, double height,
|
Future createSwapChain(double width, double height,
|
||||||
@@ -2174,9 +2180,10 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Camera> createCamera() async {
|
Future<Camera> createCamera() async {
|
||||||
var camera = SceneManager_createCamera(_sceneManager!);
|
var cameraPtr = SceneManager_createCamera(_sceneManager!);
|
||||||
var engine = Viewer_getEngine(_viewer!);
|
var engine = Viewer_getEngine(_viewer!);
|
||||||
return ThermionFFICamera(camera, engine);
|
var camera = ThermionFFICamera(cameraPtr, engine);
|
||||||
|
return camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future destroyCamera(ThermionFFICamera camera) async {
|
Future destroyCamera(ThermionFFICamera camera) async {
|
||||||
@@ -2190,6 +2197,14 @@ class ThermionViewerFFI extends ThermionViewer {
|
|||||||
SceneManager_setCamera(_sceneManager!, camera.camera);
|
SceneManager_setCamera(_sceneManager!, camera.camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future<Camera> getActiveCamera() async {
|
||||||
|
final ptr = SceneManager_getActiveCamera(_sceneManager!);
|
||||||
|
return ThermionFFICamera(ptr, Viewer_getEngine(_viewer!));
|
||||||
|
}
|
||||||
|
|
||||||
final _hooks = <Future Function()>[];
|
final _hooks = <Future Function()>[];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -18,4 +18,8 @@ abstract class Camera {
|
|||||||
ThermionEntity getEntity();
|
ThermionEntity getEntity();
|
||||||
|
|
||||||
Future setTransform(Matrix4 transform);
|
Future setTransform(Matrix4 transform);
|
||||||
|
|
||||||
|
Future<double> getNear();
|
||||||
|
Future<double> getCullingFar();
|
||||||
|
Future<double> getFocalLength();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -970,6 +970,11 @@ abstract class ThermionViewer {
|
|||||||
///
|
///
|
||||||
Future setActiveCamera(covariant Camera camera);
|
Future setActiveCamera(covariant Camera camera);
|
||||||
|
|
||||||
|
///
|
||||||
|
///
|
||||||
|
///
|
||||||
|
Future getActiveCamera();
|
||||||
|
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -310,6 +310,8 @@ namespace thermion_filament
|
|||||||
|
|
||||||
Camera* getCameraAt(size_t index);
|
Camera* getCameraAt(size_t index);
|
||||||
|
|
||||||
|
Camera* getActiveCamera();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
gltfio::AssetLoader *_assetLoader = nullptr;
|
gltfio::AssetLoader *_assetLoader = nullptr;
|
||||||
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
const ResourceLoaderWrapperImpl *const _resourceLoaderWrapper;
|
||||||
|
|||||||
@@ -217,7 +217,6 @@ extern "C"
|
|||||||
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
|
EMSCRIPTEN_KEEPALIVE void set_camera_exposure(TCamera *camera, float aperture, float shutterSpeed, float sensitivity);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix);
|
EMSCRIPTEN_KEEPALIVE void set_camera_model_matrix(TCamera *camera, double4x4 matrix);
|
||||||
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity);
|
EMSCRIPTEN_KEEPALIVE TCamera *get_camera(TViewer *viewer, EntityId entity);
|
||||||
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera);
|
|
||||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *const camera);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_model_matrix(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *const camera);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_view_matrix(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *const camera);
|
EMSCRIPTEN_KEEPALIVE double4x4 get_camera_projection_matrix(TCamera *const camera);
|
||||||
@@ -225,6 +224,10 @@ extern "C"
|
|||||||
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *const camera);
|
EMSCRIPTEN_KEEPALIVE const double *const get_camera_frustum(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far);
|
EMSCRIPTEN_KEEPALIVE void set_camera_projection_matrix(TCamera *camera, double4x4 matrix, double near, double far);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
|
EMSCRIPTEN_KEEPALIVE void set_camera_projection_from_fov(TCamera *camera, double fovInDegrees, double aspect, double near, double far, bool horizontal);
|
||||||
|
EMSCRIPTEN_KEEPALIVE double get_camera_focal_length(TCamera *const camera);
|
||||||
|
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const camera);
|
||||||
|
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *const camera);
|
||||||
|
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *const camera);
|
||||||
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera);
|
EMSCRIPTEN_KEEPALIVE double get_camera_near(TCamera *camera);
|
||||||
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera);
|
EMSCRIPTEN_KEEPALIVE double get_camera_culling_far(TCamera *camera);
|
||||||
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal);
|
EMSCRIPTEN_KEEPALIVE float get_camera_fov(TCamera *camera, bool horizontal);
|
||||||
@@ -247,6 +250,8 @@ extern "C"
|
|||||||
EMSCRIPTEN_KEEPALIVE void SceneManager_setCamera(TSceneManager *sceneManager, TCamera* camera);
|
EMSCRIPTEN_KEEPALIVE void SceneManager_setCamera(TSceneManager *sceneManager, TCamera* camera);
|
||||||
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *sceneManager);
|
EMSCRIPTEN_KEEPALIVE size_t SceneManager_getCameraCount(TSceneManager *sceneManager);
|
||||||
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraAt(TSceneManager *sceneManager, size_t index);
|
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraAt(TSceneManager *sceneManager, size_t index);
|
||||||
|
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getActiveCamera(TSceneManager *sceneManager);
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE int hide_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
|
EMSCRIPTEN_KEEPALIVE int hide_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
|
||||||
EMSCRIPTEN_KEEPALIVE int reveal_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
|
EMSCRIPTEN_KEEPALIVE int reveal_mesh(TSceneManager *sceneManager, EntityId entity, const char *meshName);
|
||||||
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled);
|
EMSCRIPTEN_KEEPALIVE void set_post_processing(TViewer *viewer, bool enabled);
|
||||||
|
|||||||
@@ -2678,6 +2678,11 @@ EntityId SceneManager::createGeometry(
|
|||||||
}
|
}
|
||||||
return _cameras[index-1];
|
return _cameras[index-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Camera* SceneManager::getActiveCamera() {
|
||||||
|
auto& camera = _view->getCamera();
|
||||||
|
return &camera;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace thermion_filament
|
} // namespace thermion_filament
|
||||||
|
|||||||
@@ -1086,6 +1086,21 @@ EMSCRIPTEN_KEEPALIVE EntityId Camera_getEntity(TCamera* tCamera) {
|
|||||||
return Entity::smuggle(camera->getEntity());
|
return Entity::smuggle(camera->getEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE double Camera_getFocalLength(TCamera *const tCamera) {
|
||||||
|
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||||
|
return camera->getFocalLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE double Camera_getNear(TCamera *const tCamera) {
|
||||||
|
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||||
|
return camera->getNear();
|
||||||
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE double Camera_getCullingFar(TCamera *const tCamera) {
|
||||||
|
auto * camera = reinterpret_cast<Camera*>(tCamera);
|
||||||
|
return camera->getCullingFar();
|
||||||
|
}
|
||||||
|
|
||||||
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId) {
|
EMSCRIPTEN_KEEPALIVE TCamera *Engine_getCameraComponent(TEngine* tEngine, EntityId entityId) {
|
||||||
auto * engine = reinterpret_cast<Engine*>(tEngine);
|
auto * engine = reinterpret_cast<Engine*>(tEngine);
|
||||||
auto * camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
auto * camera = engine->getCameraComponent(utils::Entity::import(entityId));
|
||||||
@@ -1129,4 +1144,11 @@ EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getCameraAt(TSceneManager *tSceneMana
|
|||||||
auto * camera = sceneManager->getCameraAt(index);
|
auto * camera = sceneManager->getCameraAt(index);
|
||||||
return reinterpret_cast<TCamera*>(camera);
|
return reinterpret_cast<TCamera*>(camera);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMSCRIPTEN_KEEPALIVE TCamera* SceneManager_getActiveCamera(TSceneManager *tSceneManager) {
|
||||||
|
auto * sceneManager = reinterpret_cast<SceneManager*>(tSceneManager);
|
||||||
|
auto * camera = sceneManager->getActiveCamera();
|
||||||
|
return reinterpret_cast<TCamera*>(camera);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -142,13 +142,19 @@ void main() async {
|
|||||||
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
await viewer.setBackgroundColor(1.0, 0.0, 1.0, 1.0);
|
||||||
await viewer.createGeometry(GeometryHelper.cube());
|
await viewer.createGeometry(GeometryHelper.cube());
|
||||||
await testHelper.capture(viewer, "create_camera_main_camera");
|
await testHelper.capture(viewer, "create_camera_main_camera");
|
||||||
|
|
||||||
var newCamera = await viewer.createCamera();
|
var newCamera = await viewer.createCamera();
|
||||||
await newCamera.setTransform(Matrix4.translation(Vector3(0, 0, 4)));
|
await newCamera.setTransform(Matrix4.translation(Vector3(0, 0, 4)));
|
||||||
newCamera.setLensProjection();
|
newCamera.setLensProjection();
|
||||||
await viewer.setActiveCamera(newCamera);
|
await viewer.setActiveCamera(newCamera);
|
||||||
|
|
||||||
|
expect(await viewer.getActiveCamera(), newCamera);
|
||||||
|
|
||||||
await testHelper.capture(viewer, "create_camera_new_camera");
|
await testHelper.capture(viewer, "create_camera_new_camera");
|
||||||
|
|
||||||
final mainCamera = await viewer.getMainCamera();
|
final mainCamera = await viewer.getMainCamera();
|
||||||
await viewer.setActiveCamera(mainCamera);
|
await viewer.setActiveCamera(mainCamera);
|
||||||
|
expect(await viewer.getActiveCamera(), mainCamera);
|
||||||
await testHelper.capture(viewer, "create_camera_back_to_main");
|
await testHelper.capture(viewer, "create_camera_back_to_main");
|
||||||
|
|
||||||
expect(viewer.getCameraCount(), 2);
|
expect(viewer.getCameraCount(), 2);
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:thermion_dart/thermion_dart.dart';
|
||||||
|
|
||||||
|
class CameraSelectorWidget extends StatefulWidget {
|
||||||
|
final ThermionViewer viewer;
|
||||||
|
|
||||||
|
const CameraSelectorWidget({Key? key, required this.viewer}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_CameraSelectorWidgetState createState() => _CameraSelectorWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _CameraSelectorWidgetState extends State<CameraSelectorWidget> {
|
||||||
|
int _activeIndex = 0;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
int cameraCount = widget.viewer.getCameraCount();
|
||||||
|
|
||||||
|
return Container(
|
||||||
|
height:32,
|
||||||
|
margin: const EdgeInsets.all(8),
|
||||||
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withOpacity(0.1),
|
||||||
|
blurRadius: 4,
|
||||||
|
offset: const Offset(0, 2),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
_buildCameraButton("Main", 0),
|
||||||
|
if (cameraCount > 1) const VerticalDivider(width: 16, thickness: 1),
|
||||||
|
...List.generate(cameraCount - 1, (index) {
|
||||||
|
return _buildCameraButton("${index + 1}", index + 1);
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildCameraButton(String label, int index) {
|
||||||
|
bool isActive = _activeIndex == index;
|
||||||
|
return Flexible(child:TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
if (index == 0) {
|
||||||
|
await widget.viewer.setMainCamera();
|
||||||
|
} else {
|
||||||
|
Camera camera = widget.viewer.getCameraAt(index);
|
||||||
|
await widget.viewer.setActiveCamera(camera);
|
||||||
|
}
|
||||||
|
setState(() {
|
||||||
|
_activeIndex = index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
|
minimumSize: Size.zero,
|
||||||
|
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
|
backgroundColor: isActive ? Colors.blue.withOpacity(0.1) : null,
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 10,
|
||||||
|
fontWeight: isActive ? FontWeight.bold : FontWeight.normal,
|
||||||
|
color: isActive ? Colors.blue : Colors.black87,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ library;
|
|||||||
|
|
||||||
export 'src/thermion_widget.dart';
|
export 'src/thermion_widget.dart';
|
||||||
export 'src/thermion_listener_widget.dart';
|
export 'src/thermion_listener_widget.dart';
|
||||||
|
export 'src/camera/camera_selector_widget.dart';
|
||||||
|
|||||||
Reference in New Issue
Block a user