godot-ultraleap-plugin/src/device_node.cpp
rodolpheh 8b932e3a3c Try to improve stability in editor
The more I made changes, the more it crashed. Got it to a point where
it doesn't crash when starting the editor, but it will crash when
exciting.
2023-11-08 22:47:41 +00:00

322 lines
9.5 KiB
C++

#include "device_node.h"
#include <godot_cpp/core/class_db.hpp>
#include <godot_cpp/classes/global_constants.hpp>
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/classes/node3d.hpp>
#include <godot_cpp/classes/engine.hpp>
#include <godot_cpp/variant/utility_functions.hpp>
#include <LeapC.h>
#include "ultraleap.h"
using namespace godot;
void UltraleapDeviceNode::device_added(Ref<UltraleapDevice> device) {
if (!devices.has(device->serial)) {
devices.append(device->serial);
notify_property_list_changed();
}
// If user has chosen "Any", the strategy here is to use the newly connected device
if (chosen_serial == 0) {
if (current_device != NULL && should_run()) {
unsubscribe_and_close();
}
current_device = device;
if (should_run()) {
open_and_subscribe();
}
}
// Otherwise we check for the serial and subscribe to the device
else {
if (get_tracking() != NULL) {
if ((chosen_serial - 1) < get_tracking()->devices->size()) {
if (devices[chosen_serial - 1] == device->serial) {
current_device = device;
if (should_run()) {
open_and_subscribe();
}
}
}
}
}
}
void UltraleapDeviceNode::device_removed(Ref<UltraleapDevice> device) {
if (!devices.has(device->serial)) {
return;
}
// If the device being removed is the same as the one being used by this
// node, unsubscribe and close it
if (current_device != NULL) {
if (device->serial == current_device->serial) {
unsubscribe_and_close();
current_device = Ref<UltraleapDevice>();
}
}
devices.erase(device->serial);
notify_property_list_changed();
}
void UltraleapDeviceNode::open_and_subscribe() {
if (current_device != NULL) {
current_device->open();
current_device->subscribe();
}
}
void UltraleapDeviceNode::unsubscribe_and_close() {
if (current_device != NULL) {
current_device->unsubscribe();
current_device->close();
}
}
void UltraleapDeviceNode::_bind_methods() {
PropertyInfo tracking_mode_info = PropertyInfo(
Variant::INT,
"tracking_mode",
PROPERTY_HINT_ENUM,
"Desktop, HMD, Screentop"
);
ClassDB::bind_method(D_METHOD("set_tracker", "tracker"), &UltraleapDeviceNode::set_tracker);
ClassDB::bind_method(D_METHOD("get_tracker"), &UltraleapDeviceNode::get_tracker);
ClassDB::bind_method(D_METHOD("get_last_frame"), &UltraleapDeviceNode::get_last_frame);
ClassDB::bind_method(D_METHOD("get_interpolated_frame", "time"), &UltraleapDeviceNode::get_interpolated_frame);
ClassDB::bind_method(D_METHOD("get_left_image"), &UltraleapDeviceNode::get_left_image);
ClassDB::bind_method(D_METHOD("get_right_image"), &UltraleapDeviceNode::get_right_image);
ClassDB::bind_method(D_METHOD("device_added", "device"), &UltraleapDeviceNode::device_added);
ClassDB::bind_method(D_METHOD("device_removed", "device"), &UltraleapDeviceNode::device_removed);
ClassDB::bind_method(D_METHOD("set_tracking_mode", "tracking_mode"), &UltraleapDeviceNode::set_tracking_mode, DEFVAL(0));
ClassDB::bind_method(D_METHOD("get_tracking_mode"), &UltraleapDeviceNode::get_tracking_mode);
ClassDB::bind_method(D_METHOD("set_run_in_editor", "run_in_editor"), &UltraleapDeviceNode::set_run_in_editor, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_run_in_editor"), &UltraleapDeviceNode::get_run_in_editor);
ClassDB::add_property(
"UltraleapDeviceNode",
PropertyInfo(
Variant::NODE_PATH,
"tracker",
PROPERTY_HINT_NODE_TYPE,
"UltraleapHandTracking"
),
"set_tracker",
"get_tracker"
);
ClassDB::add_property(
"UltraleapDeviceNode",
tracking_mode_info,
"set_tracking_mode",
"get_tracking_mode"
);
ClassDB::add_property(
"UltraleapDeviceNode",
PropertyInfo(
Variant::BOOL,
"run_in_editor"
),
"set_run_in_editor",
"get_run_in_editor"
);
// Signals
ClassDB::add_signal(
"UltraleapDeviceNode",
MethodInfo(
"tracking_mode_changed",
PropertyInfo(
Variant::INT,
"tracking_mode",
PROPERTY_HINT_ENUM,
"Desktop, HMD, Screentop"
)
)
);
ClassDB::add_signal(
"UltraleapDeviceNode",
MethodInfo(
"frame_received",
PropertyInfo(
Variant::OBJECT,
"frame",
PROPERTY_HINT_RESOURCE_TYPE,
"UltraleapFrame"
)
)
);
ClassDB::add_signal(
"UltraleapDeviceNode",
MethodInfo(
"image_received",
PropertyInfo(
Variant::OBJECT,
"frame",
PROPERTY_HINT_RESOURCE_TYPE,
"UltraleapImage"
)
)
);
}
void UltraleapDeviceNode::set_tracker(NodePath value) {
if (!tracker.is_empty()) {
Node* tracking = get_node_or_null(tracker);
if (tracking != NULL) {
tracking->disconnect("device_added", Callable((Object*)this, "device_added"));
}
}
Node* tracking = get_node_or_null(tracker);
if (tracking != NULL) {
tracking->connect("device_added", Callable((Object*)this, "device_added"));
}
tracker = value;
}
void UltraleapDeviceNode::_notification(int p_what) {
if (p_what == Node::NOTIFICATION_READY) {
Node *tracking_node = get_node_or_null(tracker);
if (tracking_node != NULL) {
UltraleapHandTracking* tracking = Object::cast_to<UltraleapHandTracking>(tracking_node);
// Connect to tracking signals
tracking->connect("device_added", Callable((Object*)this, "device_added"));
tracking->connect("device_removed", Callable((Object*)this, "device_removed"));
// Build a list of serial numbers to choose from
for (int i = 0; i < tracking->devices->size(); i++) {
Ref<UltraleapDevice> device = tracking->devices->get(i);
if (!devices.has(device->serial)) {
devices.append(device->serial);
}
}
}
}
else if (p_what == Node::NOTIFICATION_ENTER_TREE) {
set_process_internal(true);
}
else if (p_what == Node::NOTIFICATION_INTERNAL_PROCESS) {
if (current_device == NULL || !should_run()) {
return;
}
Ref<UltraleapFrame> new_frame = current_device->get_last_frame();
if (last_frame->id != new_frame->id) {
last_frame = new_frame;
emit_signal("frame_received", last_frame);
}
if (current_device->tracking_mode != tracking_mode) {
tracking_mode = current_device->tracking_mode;
emit_signal("tracking_mode_changed", current_device->tracking_mode);
}
}
}
void UltraleapDeviceNode::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(
PropertyInfo(
Variant::INT,
"device",
PROPERTY_HINT_ENUM,
String(",").join(devices).insert(0, "Any,")
)
);
}
bool UltraleapDeviceNode::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
if (name == "device") {
r_ret = chosen_serial;
return true;
}
return false;
}
bool UltraleapDeviceNode::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
if (name == "device") {
chosen_serial = p_value;
notify_property_list_changed();
return true;
}
return false;
}
UltraleapHandTracking* UltraleapDeviceNode::get_tracking() {
return Object::cast_to<UltraleapHandTracking>(get_node_or_null(tracker));
}
Variant UltraleapDeviceNode::get_last_frame() {
return last_frame;
}
Variant UltraleapDeviceNode::get_interpolated_frame(int64_t time) {
if (current_device == NULL) {
return Variant::NIL;
}
return current_device->get_interpolated_frame(time);
}
void UltraleapDeviceNode::set_tracking_mode(UltraleapTypes::TrackingMode value) {
// If we're in the editor, we just change the value displayed,
// otherwise we make a request on the device to change the tracking mode
if (!should_run()) {
tracking_mode = value;
}
else {
if (current_device != NULL) {
current_device->set_tracking_mode(value);
}
}
}
Variant UltraleapDeviceNode::get_left_image() {
if (current_device == NULL) {
return Variant::NIL;
}
return current_device->get_left_image();
}
Variant UltraleapDeviceNode::get_right_image() {
if (current_device == NULL) {
return Variant::NIL;
}
return current_device->get_right_image();
}
bool UltraleapDeviceNode::should_run() {
return (Engine::get_singleton()->is_editor_hint() && run_in_editor) || !Engine::get_singleton()->is_editor_hint();
}
void UltraleapDeviceNode::set_run_in_editor(bool value) {
// If we are running in the editor and have a device, we close it
if (should_run() && current_device != NULL) {
// God knows what happens if it wasn't previously opened...
unsubscribe_and_close();
}
run_in_editor = value;
// Now if we should run, let open the device
if (should_run() && current_device != NULL) {
open_and_subscribe();
}
}