845 lines
27 KiB
C++
845 lines
27 KiB
C++
#include "ultraleap.h"
|
|
|
|
#include <godot_cpp/core/class_db.hpp>
|
|
|
|
#include <godot_cpp/classes/global_constants.hpp>
|
|
#include <godot_cpp/variant/utility_functions.hpp>
|
|
#include <godot_cpp/variant/vector3.hpp>
|
|
#include <godot_cpp/classes/node3d.hpp>
|
|
#include <godot_cpp/classes/engine.hpp>
|
|
|
|
#include <LeapC.h>
|
|
|
|
#include <thread>
|
|
#include <functional>
|
|
|
|
#include "frame.h"
|
|
#include "allocator.h"
|
|
|
|
#ifdef ANDROID_ENABLED
|
|
#include <android/log.h>
|
|
|
|
#define LOG_TAG "ultraleap.cpp"
|
|
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
|
|
#endif
|
|
|
|
using namespace godot;
|
|
|
|
UltraleapHandTracking::~UltraleapHandTracking() {
|
|
UtilityFunctions::print("Destroying UltraleapHandTracking");
|
|
|
|
if (is_running) {
|
|
UtilityFunctions::print("Stopping the tracking thread");
|
|
keep_running = false;
|
|
messageLoop.join();
|
|
}
|
|
|
|
dispose_ultraleap();
|
|
|
|
#if ANDROID_ENABLED
|
|
binder = NULL;
|
|
#endif
|
|
}
|
|
|
|
void UltraleapHandTracking::dispose_ultraleap() {
|
|
if (opened && connectionHandle) {
|
|
UtilityFunctions::print("Closing the connection");
|
|
LeapCloseConnection(connectionHandle);
|
|
opened = false;
|
|
}
|
|
|
|
if (connectionHandle) {
|
|
UtilityFunctions::print("Destroying the connection");
|
|
LeapDestroyConnection(connectionHandle);
|
|
connectionHandle = NULL;
|
|
}
|
|
|
|
#if ANDROID_ENABLED
|
|
if (binder != NULL) {
|
|
if (binder->call("IsBound")) {
|
|
binder->call("Unbind");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void UltraleapHandTracking::_bind_methods() {
|
|
PropertyInfo tracking_mode_info = PropertyInfo(
|
|
Variant::INT,
|
|
"tracking_mode",
|
|
PROPERTY_HINT_ENUM,
|
|
"Desktop, HMD, Screentop"
|
|
);
|
|
|
|
ClassDB::bind_method(D_METHOD("start"), &UltraleapHandTracking::start);
|
|
ClassDB::bind_method(D_METHOD("stop"), &UltraleapHandTracking::stop);
|
|
|
|
ClassDB::bind_method(D_METHOD("is_connected"), &UltraleapHandTracking::is_connected);
|
|
ClassDB::bind_method(D_METHOD("is_started"), &UltraleapHandTracking::is_started);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_last_frame", "last_frame"), &UltraleapHandTracking::set_last_frame);
|
|
ClassDB::bind_method(D_METHOD("get_last_frame"), &UltraleapHandTracking::get_last_frame);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_tracking_mode", "tracking_mode"), &UltraleapHandTracking::set_tracking_mode, DEFVAL(0));
|
|
ClassDB::bind_method(D_METHOD("get_tracking_mode"), &UltraleapHandTracking::get_tracking_mode);
|
|
|
|
ClassDB::bind_method(D_METHOD("get_left_image"), &UltraleapHandTracking::get_left_image);
|
|
ClassDB::bind_method(D_METHOD("get_right_image"), &UltraleapHandTracking::get_right_image);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_devices", "devices"), &UltraleapHandTracking::set_devices);
|
|
ClassDB::bind_method(D_METHOD("get_devices"), &UltraleapHandTracking::get_devices);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_service_ip", "service_ip"), &UltraleapHandTracking::set_service_ip);
|
|
ClassDB::bind_method(D_METHOD("get_service_ip"), &UltraleapHandTracking::get_service_ip);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_service_port", "service_port"), &UltraleapHandTracking::set_service_port);
|
|
ClassDB::bind_method(D_METHOD("get_service_port"), &UltraleapHandTracking::get_service_port);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_autostart", "enable"), &UltraleapHandTracking::set_autostart);
|
|
ClassDB::bind_method(D_METHOD("get_autostart"), &UltraleapHandTracking::get_autostart);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_enable_images", "enable"), &UltraleapHandTracking::set_enable_images);
|
|
ClassDB::bind_method(D_METHOD("get_enable_images"), &UltraleapHandTracking::get_enable_images);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_images_policy", "value"), &UltraleapHandTracking::set_images_policy);
|
|
ClassDB::bind_method(D_METHOD("set_allow_pause_resume_policy", "value"), &UltraleapHandTracking::set_allow_pause_resume_policy);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_primary_device", "device"), &UltraleapHandTracking::set_primary_device);
|
|
ClassDB::bind_method(D_METHOD("get_primary_device"), &UltraleapHandTracking::get_primary_device);
|
|
|
|
ClassDB::bind_method(D_METHOD("set_pause", "value"), &UltraleapHandTracking::set_pause);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
PropertyInfo(
|
|
Variant::OBJECT,
|
|
"last_frame",
|
|
PROPERTY_HINT_RESOURCE_TYPE,
|
|
"UltraleapFrame",
|
|
PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_EDITOR
|
|
),
|
|
"set_last_frame",
|
|
"get_last_frame"
|
|
);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
tracking_mode_info,
|
|
"set_tracking_mode",
|
|
"get_tracking_mode"
|
|
);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
PropertyInfo(
|
|
Variant::ARRAY,
|
|
"devices",
|
|
PROPERTY_HINT_ARRAY_TYPE,
|
|
"UltraleapDevice",
|
|
PROPERTY_USAGE_READ_ONLY | PROPERTY_USAGE_EDITOR
|
|
),
|
|
"set_devices",
|
|
"get_devices"
|
|
);
|
|
|
|
ClassDB::add_property_group(
|
|
"UltraleapHandTracking",
|
|
"Connection",
|
|
"service"
|
|
);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
PropertyInfo(
|
|
Variant::STRING,
|
|
"service_ip"
|
|
),
|
|
"set_service_ip",
|
|
"get_service_ip"
|
|
);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
PropertyInfo(
|
|
Variant::INT,
|
|
"service_port"
|
|
),
|
|
"set_service_port",
|
|
"get_service_port"
|
|
);
|
|
|
|
ClassDB::add_property_group(
|
|
"UltraleapHandTracking",
|
|
"Startup",
|
|
"startup"
|
|
);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"startup_autostart"
|
|
),
|
|
"set_autostart",
|
|
"get_autostart"
|
|
);
|
|
|
|
ClassDB::add_property(
|
|
"UltraleapHandTracking",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"startup_enable_images"
|
|
),
|
|
"set_enable_images",
|
|
"get_enable_images"
|
|
);
|
|
|
|
// SIGNALS
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"connection_status_changed",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"connected"
|
|
)
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"tracking_mode_changed",
|
|
tracking_mode_info
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"device_added",
|
|
PropertyInfo(
|
|
Variant::OBJECT,
|
|
"device",
|
|
PROPERTY_HINT_RESOURCE_TYPE,
|
|
"UltraleapDevice"
|
|
)
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"device_removed",
|
|
PropertyInfo(
|
|
Variant::OBJECT,
|
|
"device",
|
|
PROPERTY_HINT_RESOURCE_TYPE,
|
|
"UltraleapDevice"
|
|
)
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"images_policy_changed",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"state"
|
|
)
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"background_frames_policy_changed",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"state"
|
|
)
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"map_points_policy_changed",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"state"
|
|
)
|
|
)
|
|
);
|
|
|
|
ClassDB::add_signal(
|
|
"UltraleapHandTracking",
|
|
MethodInfo(
|
|
"allow_pause_resume_policy_changed",
|
|
PropertyInfo(
|
|
Variant::BOOL,
|
|
"state"
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
void UltraleapHandTracking::start() {
|
|
if (started) {
|
|
UtilityFunctions::print("The tracking is already started");
|
|
return;
|
|
}
|
|
|
|
UtilityFunctions::print("Starting the tracking");
|
|
|
|
#ifdef ANDROID_ENABLED
|
|
if (binder == NULL) {
|
|
ALOGI("Couldn't get the service binder, stopping");
|
|
return;
|
|
}
|
|
|
|
if (!binder->call("IsBound")) {
|
|
ALOGI("Binding to the service");
|
|
binder->call("Bind");
|
|
}
|
|
|
|
// This will freeze the app if the service doesn't bind
|
|
while (!binder->call("IsBound")) {
|
|
ALOGI("Not bound yet");
|
|
}
|
|
#endif
|
|
|
|
started = true;
|
|
|
|
LEAP_CONNECTION_CONFIG config;
|
|
|
|
// Set connection to multi-device aware
|
|
memset(&config, 0, sizeof(config));
|
|
config.size = sizeof(config);
|
|
config.flags = eLeapConnectionConfig_MultiDeviceAware;
|
|
config.server_namespace = generate_connection_payload().utf8().get_data();
|
|
|
|
if(connectionHandle || LeapCreateConnection(&config, &connectionHandle) == eLeapRS_Success) {
|
|
eLeapRS result = LeapOpenConnection(connectionHandle);
|
|
if(result == eLeapRS_Success) {
|
|
opened = true;
|
|
|
|
{
|
|
LEAP_ALLOCATOR allocator = { allocate, deallocate, NULL };
|
|
LeapSetAllocator(connectionHandle, &allocator);
|
|
}
|
|
|
|
if (!Engine::get_singleton()->is_editor_hint() && enable_images) {
|
|
LeapSetPolicyFlags(connectionHandle, eLeapPolicyFlag_Images, 0);
|
|
}
|
|
|
|
// Create the message poll thread
|
|
messageLoop = std::thread(&UltraleapHandTracking::serviceMessageLoop, std::ref(*this));
|
|
}
|
|
}
|
|
}
|
|
|
|
void UltraleapHandTracking::stop() {
|
|
if (!started) {
|
|
UtilityFunctions::print("Tracking already stopped");
|
|
return;
|
|
}
|
|
|
|
UtilityFunctions::print("Trying to stop tracking...");
|
|
|
|
if (keep_running) {
|
|
UtilityFunctions::print("Turning off flag of thread");
|
|
keep_running = false;
|
|
}
|
|
|
|
// If the polling thread is still alive, we defer calling the stop function
|
|
// again on the next frame, and this until it's dead, then we will clean
|
|
// the connection
|
|
if (is_running) {
|
|
call_deferred("stop");
|
|
return;
|
|
}
|
|
|
|
messageLoop.join();
|
|
dispose_ultraleap();
|
|
|
|
started = false;
|
|
|
|
UtilityFunctions::print("Tracking stopped!");
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_connection_event(const LEAP_CONNECTION_EVENT *evt) {
|
|
events.push({ "connection_status_changed", true });
|
|
connected = true;
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_connection_lost_event(const LEAP_CONNECTION_LOST_EVENT *event) {
|
|
events.push({ "connection_status_changed", false });
|
|
connected = false;
|
|
|
|
// TODO: write something more pretty
|
|
devices->devices.clear();
|
|
}
|
|
|
|
void UltraleapHandTracking::serviceMessageLoop() {
|
|
LEAP_CONNECTION_MESSAGE msg;
|
|
eLeapRS result;
|
|
|
|
keep_running = true;
|
|
is_running = true;
|
|
|
|
while (keep_running) {
|
|
result = LeapPollConnection(connectionHandle, 100, &msg);
|
|
|
|
if (result != eLeapRS_Success && result != eLeapRS_Timeout) {
|
|
UtilityFunctions::print(UltraleapTypes::ultraleap_result_to_string(result));
|
|
continue;
|
|
}
|
|
|
|
// Polling may have taken some time, re-check exit condition
|
|
if (!keep_running) {
|
|
break;
|
|
}
|
|
|
|
switch (msg.type){
|
|
case eLeapEventType_Connection:
|
|
handle_connection_event(msg.connection_event);
|
|
break;
|
|
case eLeapEventType_ConnectionLost:
|
|
handle_connection_lost_event(msg.connection_lost_event);
|
|
break;
|
|
case eLeapEventType_Device:
|
|
handle_device_event(msg.device_event);
|
|
break;
|
|
case eLeapEventType_DeviceLost:
|
|
handle_device_lost_event(msg.device_event);
|
|
break;
|
|
case eLeapEventType_DeviceFailure:
|
|
UtilityFunctions::print("A device failed!");
|
|
handle_device_lost_event(msg.device_event);
|
|
break;
|
|
case eLeapEventType_Tracking:
|
|
handle_tracking_event(msg.tracking_event, msg.device_id);
|
|
break;
|
|
case eLeapEventType_ImageComplete:
|
|
break;
|
|
case eLeapEventType_ImageRequestError:
|
|
break;
|
|
case eLeapEventType_LogEvent:
|
|
break;
|
|
case eLeapEventType_Policy:
|
|
handle_policy_change_event(msg.policy_event);
|
|
break;
|
|
case eLeapEventType_ConfigChange:
|
|
break;
|
|
case eLeapEventType_ConfigResponse:
|
|
break;
|
|
case eLeapEventType_Image:
|
|
handle_image_event(msg.image_event, msg.device_id);
|
|
break;
|
|
case eLeapEventType_PointMappingChange:
|
|
break;
|
|
case eLeapEventType_TrackingMode:
|
|
// TODO: Check if having this and the policy event use the same path to notify a change in tracking mode
|
|
handle_tracking_mode_event(msg.tracking_mode_event, msg.device_id);
|
|
break;
|
|
case eLeapEventType_LogEvents:
|
|
break;
|
|
case eLeapEventType_HeadPose:
|
|
break;
|
|
case eLeapEventType_IMU:
|
|
break;
|
|
case eLeapEventType_DeviceStatusChange:
|
|
UtilityFunctions::print("Device status change!");
|
|
handle_device_status_change_event(msg.device_status_change_event, msg.device_id);
|
|
break;
|
|
case eLeapEventType_DroppedFrame:
|
|
break;
|
|
case eLeapEventType_Eyes:
|
|
break;
|
|
case eLeapEventType_None:
|
|
break;
|
|
default:
|
|
UtilityFunctions::print("Unhandled message type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
is_running = false;
|
|
}
|
|
|
|
UltraleapTypes::TrackingMode UltraleapHandTracking::get_tracking_mode() {
|
|
if (primary_device == NULL) {
|
|
return UltraleapTypes::TrackingMode::Desktop;
|
|
}
|
|
|
|
return primary_device->tracking_mode;
|
|
}
|
|
|
|
void UltraleapHandTracking::set_tracking_mode(UltraleapTypes::TrackingMode value) {
|
|
if (primary_device == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (value != primary_device->tracking_mode) {
|
|
uint64_t set_flag = 0;
|
|
uint64_t clear_flag = 0;
|
|
if (value == UltraleapTypes::TrackingMode::Desktop) {
|
|
clear_flag = eLeapPolicyFlag_OptimizeHMD | eLeapPolicyFlag_OptimizeScreenTop;
|
|
}
|
|
else if (value == UltraleapTypes::TrackingMode::HMD) {
|
|
set_flag = eLeapPolicyFlag_OptimizeHMD;
|
|
clear_flag = eLeapPolicyFlag_OptimizeScreenTop;
|
|
}
|
|
else if (value == UltraleapTypes::TrackingMode::Screentop) {
|
|
clear_flag = eLeapPolicyFlag_OptimizeHMD;
|
|
set_flag = eLeapPolicyFlag_OptimizeScreenTop;
|
|
}
|
|
else {
|
|
UtilityFunctions::print("Invalid value for tracking mode");
|
|
}
|
|
LeapSetPolicyFlagsEx(connectionHandle, primary_device->device, set_flag, clear_flag);
|
|
}
|
|
}
|
|
|
|
void UltraleapHandTracking::set_images_policy(bool value) {
|
|
uint64_t set_flag = value ? UltraleapTypes::set_policy_flag(0, UltraleapTypes::PolicyFlag::Images) : 0;
|
|
uint64_t clear_flag = !value ? UltraleapTypes::set_policy_flag(0, UltraleapTypes::PolicyFlag::Images) : 0;
|
|
LeapSetPolicyFlags(connectionHandle, set_flag, clear_flag);
|
|
}
|
|
|
|
void UltraleapHandTracking::set_background_frames_policy(bool value) {
|
|
set_policy(UltraleapTypes::PolicyFlag::BackgroundFrames, value);
|
|
}
|
|
|
|
void UltraleapHandTracking::set_map_points_policy(bool value) {
|
|
set_policy(UltraleapTypes::PolicyFlag::MapPoints, value);
|
|
}
|
|
|
|
void UltraleapHandTracking::set_allow_pause_resume_policy(bool value) {
|
|
set_policy(UltraleapTypes::PolicyFlag::AllowPauseResume, value);
|
|
// Apparently, there's no policy changed event with this so we force the service to send an update
|
|
// However it looks like it never changes anyway, maybe it's deprecated...
|
|
LeapSetPolicyFlags(connectionHandle, 0, 0);
|
|
}
|
|
|
|
void UltraleapHandTracking::set_policy(UltraleapTypes::PolicyFlag flag, bool value) {
|
|
uint64_t set_flags = value ? UltraleapTypes::set_policy_flag(0, flag) : 0;
|
|
uint64_t clear_flags = !value ? UltraleapTypes::set_policy_flag(0, flag) : 0;
|
|
LeapSetPolicyFlags(connectionHandle, set_flags, clear_flags);
|
|
}
|
|
|
|
bool UltraleapHandTracking::get_images_policy() {
|
|
return get_policy(UltraleapTypes::PolicyFlag::Images);
|
|
}
|
|
|
|
bool UltraleapHandTracking::get_policy(UltraleapTypes::PolicyFlag flag) {
|
|
return UltraleapTypes::read_policy_flag(policy_flags, flag);
|
|
}
|
|
|
|
void UltraleapHandTracking::set_pause(bool value) {
|
|
eLeapRS result = LeapSetPause(connectionHandle, value);
|
|
if (result == eLeapRS_Success) {
|
|
// Maybe send a signal here ?
|
|
}
|
|
else {
|
|
UtilityFunctions::print(UltraleapTypes::ultraleap_result_to_string(result));
|
|
}
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_tracking_event(const LEAP_TRACKING_EVENT* event, uint32_t device_id) {
|
|
// Get a device from our list and notify it of a new tracking event
|
|
// Stores it in this node if this is the primary device
|
|
|
|
Ref<UltraleapDevice> dev = devices->find_by_id(device_id);
|
|
|
|
// If we don't find the device, it might not be registered and that
|
|
// could be a problem. Maybe we should notify the user?
|
|
if (dev == NULL) {
|
|
return;
|
|
}
|
|
|
|
dev->on_frame_received(event);
|
|
|
|
// Commenting for now, might remove later. The getter now get the frame
|
|
// from the primary device instead of storing it.
|
|
// if (primary_device != NULL && primary_device->id == device_id) {
|
|
// last_frame_ref = primary_device->get_last_frame();
|
|
// }
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_image_event(const LEAP_IMAGE_EVENT* event, uint32_t device_id) {
|
|
// TODO: Use all information from the event, not just the image
|
|
|
|
// Get a device from our list and notify it of a new image event
|
|
// Stores it in this node if this is the primary device
|
|
|
|
Ref<UltraleapDevice> dev = devices->find_by_id(device_id);
|
|
|
|
// If we don't find the device, it might not be registered and that
|
|
// could be a problem. Maybe we should notify the user?
|
|
if (dev == NULL) {
|
|
return;
|
|
}
|
|
|
|
dev->on_image_received(event->image);
|
|
|
|
// Commenting for now, might remove later. The getters now get the images
|
|
// from the primary device instead of storing them.
|
|
// if (primary_device != NULL && primary_device->id == device_id) {
|
|
// left_image_ref = primary_device->left_image_ref;
|
|
// right_image_ref = primary_device->right_image_ref;
|
|
// }
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_policy_change_event(const LEAP_POLICY_EVENT* event) {
|
|
uint32_t flags = event->current_policy;
|
|
|
|
// If current policy flags are set to UINT32_MAX, that means this is the
|
|
// first time we get the policies. In this case we just store it and don't
|
|
// broadcast the signals
|
|
// Edit: we actually want to notify our application of all the policy flags
|
|
// so we will just put in cache the inverse bits of the policy flags,
|
|
// and we will comment the return
|
|
if (policy_flags == UINT32_MAX) {
|
|
UtilityFunctions::print("Received policies for the first time");
|
|
policy_flags = ~flags;
|
|
//return;
|
|
}
|
|
|
|
// If no changes in policies, we can ignore it
|
|
if (policy_flags == flags) {
|
|
return;
|
|
}
|
|
|
|
bool previous_images_policy = UltraleapTypes::read_policy_flag(policy_flags, UltraleapTypes::PolicyFlag::Images);
|
|
bool previous_background_frames_policy = UltraleapTypes::read_policy_flag(policy_flags, UltraleapTypes::PolicyFlag::BackgroundFrames);
|
|
bool previous_map_points_policy = UltraleapTypes::read_policy_flag(policy_flags, UltraleapTypes::PolicyFlag::MapPoints);
|
|
bool previous_allow_pause_resume_policy = UltraleapTypes::read_policy_flag(policy_flags, UltraleapTypes::PolicyFlag::AllowPauseResume);
|
|
|
|
bool current_images_policy = UltraleapTypes::read_policy_flag(flags, UltraleapTypes::PolicyFlag::Images);
|
|
bool current_background_frames_policy = UltraleapTypes::read_policy_flag(flags, UltraleapTypes::PolicyFlag::BackgroundFrames);
|
|
bool current_map_points_policy = UltraleapTypes::read_policy_flag(flags, UltraleapTypes::PolicyFlag::MapPoints);
|
|
bool current_allow_pause_resume_policy = UltraleapTypes::read_policy_flag(flags, UltraleapTypes::PolicyFlag::AllowPauseResume);
|
|
|
|
if (current_images_policy != previous_images_policy) {
|
|
events.push({ "images_policy_changed", current_images_policy });
|
|
}
|
|
|
|
if (current_background_frames_policy != previous_background_frames_policy) {
|
|
events.push({ "background_frames_policy_changed", current_background_frames_policy });
|
|
}
|
|
|
|
if (current_map_points_policy != previous_map_points_policy) {
|
|
events.push({ "map_points_policy_changed", current_map_points_policy });
|
|
}
|
|
|
|
if (current_allow_pause_resume_policy != previous_allow_pause_resume_policy) {
|
|
events.push({ "allow_pause_resume_policy_changed", current_allow_pause_resume_policy });
|
|
}
|
|
|
|
policy_flags = flags;
|
|
}
|
|
|
|
|
|
void UltraleapHandTracking::handle_tracking_mode_event(const LEAP_TRACKING_MODE_EVENT* event, uint32_t device_id) {
|
|
eLeapTrackingMode current_tracking_mode = event->current_tracking_mode;
|
|
UltraleapTypes::TrackingMode tm = default_tracking_mode;
|
|
|
|
// Parse into a defined type
|
|
if (current_tracking_mode == eLeapTrackingMode_HMD) {
|
|
tm = UltraleapTypes::TrackingMode::HMD;
|
|
}
|
|
else if (current_tracking_mode == eLeapTrackingMode_ScreenTop) {
|
|
tm = UltraleapTypes::TrackingMode::Screentop;
|
|
}
|
|
else if (current_tracking_mode == eLeapTrackingMode_Desktop) {
|
|
tm = UltraleapTypes::TrackingMode::Desktop;
|
|
}
|
|
|
|
if (primary_device != NULL && device_id == primary_device->id) {
|
|
if (primary_device->tracking_mode != tm) {
|
|
events.push({ "tracking_mode_changed", tm });
|
|
}
|
|
}
|
|
|
|
Ref<UltraleapDevice> dev = devices->find_by_id(device_id);
|
|
if (dev != NULL && dev->tracking_mode != tm) {
|
|
dev->tracking_mode_changed(tm);
|
|
}
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_device_event(const LEAP_DEVICE_EVENT* event) {
|
|
Ref<UltraleapDevice> dev = create_device(event->device);
|
|
if (!devices->has_device(dev)) {
|
|
devices->add_device(dev);
|
|
events.push({ "device_added", dev });
|
|
}
|
|
else {
|
|
UtilityFunctions::print("Device was already in the list, updating");
|
|
devices->remove_device(dev);
|
|
devices->add_device(dev);
|
|
events.push({ "device_added", dev });
|
|
}
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_device_lost_event(const LEAP_DEVICE_EVENT* event) {
|
|
UtilityFunctions::print("Device lost");
|
|
|
|
Ref<UltraleapDevice> dev = create_device(event->device);
|
|
if (devices->has_device(dev)) {
|
|
devices->remove_device(dev);
|
|
events.push({ "device_removed", dev });
|
|
}
|
|
else {
|
|
UtilityFunctions::print("Device was not in the list");
|
|
}
|
|
}
|
|
|
|
void UltraleapHandTracking::handle_device_status_change_event(const LEAP_DEVICE_STATUS_CHANGE_EVENT* event, uint32_t device_id) {
|
|
// Not implemented yet, I don't know what is deprecated or not
|
|
}
|
|
|
|
void UltraleapHandTracking::refresh_device_list() {
|
|
UtilityFunctions::print("Refresh device list");
|
|
|
|
uint32_t device_count = 0;
|
|
eLeapRS result = LeapGetDeviceList(connectionHandle, NULL, &device_count);
|
|
if (result != eLeapRS_Success) {
|
|
UtilityFunctions::print("Error while counting the number of devices");
|
|
}
|
|
|
|
LEAP_DEVICE_REF* devices_ref = (LEAP_DEVICE_REF*)memalloc(device_count * sizeof(LEAP_DEVICE_REF));
|
|
result = LeapGetDeviceList(connectionHandle, devices_ref, &device_count);
|
|
|
|
if (result != eLeapRS_Success) {
|
|
memfree(devices_ref);
|
|
UtilityFunctions::print("Error while enumerating the devices");
|
|
}
|
|
|
|
devices->devices.clear();
|
|
|
|
for (int index = 0; index < device_count; index++) {
|
|
Ref<UltraleapDevice> dev = create_device(devices_ref[index]);
|
|
devices->add_device(dev);
|
|
}
|
|
|
|
memfree(devices_ref);
|
|
|
|
notify_property_list_changed();
|
|
}
|
|
|
|
Ref<UltraleapDevice> UltraleapHandTracking::create_device(LEAP_DEVICE_REF ref) {
|
|
LEAP_DEVICE device;
|
|
LeapOpenDevice(ref, &device);
|
|
|
|
LEAP_DEVICE_INFO deviceInfo;
|
|
memset(&deviceInfo, 0, sizeof(deviceInfo));
|
|
|
|
// Use stack memory to allocate for the serial number field.
|
|
char serial[1000];
|
|
memset(serial, 0, sizeof(serial));
|
|
deviceInfo.serial = serial;
|
|
deviceInfo.serial_length = sizeof(serial) - 1;
|
|
deviceInfo.size = sizeof(deviceInfo);
|
|
|
|
LeapGetDeviceInfo(device, &deviceInfo);
|
|
|
|
Ref<UltraleapDevice> dev = Ref<UltraleapDevice>(memnew(UltraleapDevice));
|
|
dev->serial = String(deviceInfo.serial);
|
|
dev->baseline = deviceInfo.baseline;
|
|
dev->id = ref.id;
|
|
|
|
dev->device_ref = ref;
|
|
dev->connection = connectionHandle;
|
|
|
|
UtilityFunctions::print("Created device with ID: ", ref.id, ", type: ", deviceInfo.pid, ", serial number: ", deviceInfo.serial);
|
|
|
|
LeapCloseDevice(device);
|
|
|
|
return dev;
|
|
}
|
|
|
|
void UltraleapHandTracking::_notification(int p_what) {
|
|
//UtilityFunctions::print(p_what);
|
|
if (p_what == Node::NOTIFICATION_ENTER_TREE) {
|
|
set_process_internal(true);
|
|
}
|
|
else if (p_what == Node::NOTIFICATION_INTERNAL_PROCESS) {
|
|
while (!events.empty()) {
|
|
event ev = events.front();
|
|
emit_signal(ev.signal, ev.arg);
|
|
events.pop();
|
|
}
|
|
}
|
|
else if (p_what == Node::NOTIFICATION_READY) {
|
|
#if ANDROID_ENABLED
|
|
// Get and store the binder
|
|
if (Engine::get_singleton()->has_singleton("UltraleapBinder")) {
|
|
binder = Engine::get_singleton()->get_singleton("UltraleapBinder");
|
|
}
|
|
#endif
|
|
|
|
// For now we will also start automatically if we're in the editor, so that we can have data for tool scripts
|
|
if (autostart || Engine::get_singleton()->is_editor_hint()) {
|
|
start();
|
|
}
|
|
}
|
|
}
|
|
|
|
String UltraleapHandTracking::generate_connection_payload() {
|
|
Array values = Array();
|
|
values.append(service_ip);
|
|
values.append(service_port);
|
|
|
|
String payload = String("{\"tracking_server_ip\": \"%0\", \"tracking_server_port\": %1}");
|
|
return payload.format(values, "%_");
|
|
}
|
|
|
|
void UltraleapHandTracking::set_primary_device(Ref<UltraleapDevice> device) {
|
|
if (primary_device == NULL || primary_device->id != device->id) {
|
|
if (primary_device != NULL && primary_device->id != device->id) {
|
|
LeapCloseDevice(primary_device->device);
|
|
}
|
|
// Pretty hack-ish, we open the device and re-store the handle in the UltraleapDevice object
|
|
LeapOpenDevice(device->device_ref, &(device->device));
|
|
LeapCreateClockRebaser(&(device->rebaser));
|
|
|
|
primary_device = device;
|
|
|
|
LeapSetPrimaryDevice(connectionHandle, device->device, false);
|
|
}
|
|
}
|
|
|
|
Variant UltraleapHandTracking::get_primary_device() {
|
|
return primary_device;
|
|
}
|
|
|
|
Variant UltraleapHandTracking::get_last_frame() {
|
|
// Uuuuh... don't like this part
|
|
if (primary_device == NULL) {
|
|
return last_frame_ref;
|
|
}
|
|
|
|
return primary_device->get_last_frame();
|
|
}
|
|
|
|
Variant UltraleapHandTracking::get_left_image() {
|
|
// Uuuuh... don't like this part
|
|
if (primary_device == NULL) {
|
|
return left_image_ref;
|
|
}
|
|
|
|
return primary_device->get_left_image();
|
|
}
|
|
|
|
Variant UltraleapHandTracking::get_right_image() {
|
|
// Uuuuh... don't like this part
|
|
if (primary_device == NULL) {
|
|
return right_image_ref;
|
|
}
|
|
|
|
return primary_device->get_right_image();
|
|
} |