1 /*************************************************************************/
2 /* arvr_interface_gdnative.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30
31 #include "arvr_interface_gdnative.h"
32 #include "main/input_default.h"
33 #include "servers/arvr/arvr_positional_tracker.h"
34 #include "servers/visual/visual_server_globals.h"
35
_bind_methods()36 void ARVRInterfaceGDNative::_bind_methods() {
37 ADD_PROPERTY_DEFAULT("interface_is_initialized", false);
38 ADD_PROPERTY_DEFAULT("ar_is_anchor_detection_enabled", false);
39 }
40
ARVRInterfaceGDNative()41 ARVRInterfaceGDNative::ARVRInterfaceGDNative() {
42 print_verbose("Construct gdnative interface\n");
43
44 // we won't have our data pointer until our library gets set
45 data = NULL;
46
47 interface = NULL;
48 }
49
~ARVRInterfaceGDNative()50 ARVRInterfaceGDNative::~ARVRInterfaceGDNative() {
51 print_verbose("Destruct gdnative interface\n");
52
53 if (interface != NULL && is_initialized()) {
54 uninitialize();
55 };
56
57 // cleanup after ourselves
58 cleanup();
59 }
60
cleanup()61 void ARVRInterfaceGDNative::cleanup() {
62 if (interface != NULL) {
63 interface->destructor(data);
64 data = NULL;
65 interface = NULL;
66 }
67 }
68
set_interface(const godot_arvr_interface_gdnative * p_interface)69 void ARVRInterfaceGDNative::set_interface(const godot_arvr_interface_gdnative *p_interface) {
70 // this should only be called once, just being paranoid..
71 if (interface) {
72 cleanup();
73 }
74
75 // bind to our interface
76 interface = p_interface;
77
78 // Now we do our constructing...
79 data = interface->constructor((godot_object *)this);
80 }
81
get_name() const82 StringName ARVRInterfaceGDNative::get_name() const {
83
84 ERR_FAIL_COND_V(interface == NULL, StringName());
85
86 godot_string result = interface->get_name(data);
87
88 StringName name = *(String *)&result;
89
90 godot_string_destroy(&result);
91
92 return name;
93 }
94
get_capabilities() const95 int ARVRInterfaceGDNative::get_capabilities() const {
96 int capabilities;
97
98 ERR_FAIL_COND_V(interface == NULL, 0); // 0 = None
99
100 capabilities = interface->get_capabilities(data);
101
102 return capabilities;
103 }
104
get_anchor_detection_is_enabled() const105 bool ARVRInterfaceGDNative::get_anchor_detection_is_enabled() const {
106
107 ERR_FAIL_COND_V(interface == NULL, false);
108
109 return interface->get_anchor_detection_is_enabled(data);
110 }
111
set_anchor_detection_is_enabled(bool p_enable)112 void ARVRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
113
114 ERR_FAIL_COND(interface == NULL);
115
116 interface->set_anchor_detection_is_enabled(data, p_enable);
117 }
118
get_camera_feed_id()119 int ARVRInterfaceGDNative::get_camera_feed_id() {
120
121 ERR_FAIL_COND_V(interface == NULL, 0);
122
123 if ((interface->version.major > 1) || ((interface->version.major) == 1 && (interface->version.minor >= 1))) {
124 return (unsigned int)interface->get_camera_feed_id(data);
125 } else {
126 return 0;
127 }
128 }
129
is_stereo()130 bool ARVRInterfaceGDNative::is_stereo() {
131 bool stereo;
132
133 ERR_FAIL_COND_V(interface == NULL, false);
134
135 stereo = interface->is_stereo(data);
136
137 return stereo;
138 }
139
is_initialized() const140 bool ARVRInterfaceGDNative::is_initialized() const {
141
142 ERR_FAIL_COND_V(interface == NULL, false);
143
144 return interface->is_initialized(data);
145 }
146
initialize()147 bool ARVRInterfaceGDNative::initialize() {
148 ERR_FAIL_COND_V(interface == NULL, false);
149
150 bool initialized = interface->initialize(data);
151
152 if (initialized) {
153 // if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
154
155 ARVRServer *arvr_server = ARVRServer::get_singleton();
156 if ((arvr_server != NULL) && (arvr_server->get_primary_interface() == NULL)) {
157 arvr_server->set_primary_interface(this);
158 };
159 };
160
161 return initialized;
162 }
163
uninitialize()164 void ARVRInterfaceGDNative::uninitialize() {
165 ERR_FAIL_COND(interface == NULL);
166
167 ARVRServer *arvr_server = ARVRServer::get_singleton();
168 if (arvr_server != NULL) {
169 // Whatever happens, make sure this is no longer our primary interface
170 arvr_server->clear_primary_interface_if(this);
171 }
172
173 interface->uninitialize(data);
174 }
175
get_render_targetsize()176 Size2 ARVRInterfaceGDNative::get_render_targetsize() {
177
178 ERR_FAIL_COND_V(interface == NULL, Size2());
179
180 godot_vector2 result = interface->get_render_targetsize(data);
181 Vector2 *vec = (Vector2 *)&result;
182
183 return *vec;
184 }
185
get_transform_for_eye(ARVRInterface::Eyes p_eye,const Transform & p_cam_transform)186 Transform ARVRInterfaceGDNative::get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) {
187 Transform *ret;
188
189 ERR_FAIL_COND_V(interface == NULL, Transform());
190
191 godot_transform t = interface->get_transform_for_eye(data, (int)p_eye, (godot_transform *)&p_cam_transform);
192
193 ret = (Transform *)&t;
194
195 return *ret;
196 }
197
get_projection_for_eye(ARVRInterface::Eyes p_eye,real_t p_aspect,real_t p_z_near,real_t p_z_far)198 CameraMatrix ARVRInterfaceGDNative::get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
199 CameraMatrix cm;
200
201 ERR_FAIL_COND_V(interface == NULL, CameraMatrix());
202
203 interface->fill_projection_for_eye(data, (godot_real *)cm.matrix, (godot_int)p_eye, p_aspect, p_z_near, p_z_far);
204
205 return cm;
206 }
207
get_external_texture_for_eye(ARVRInterface::Eyes p_eye)208 unsigned int ARVRInterfaceGDNative::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) {
209
210 ERR_FAIL_COND_V(interface == NULL, 0);
211
212 if ((interface->version.major > 1) || ((interface->version.major) == 1 && (interface->version.minor >= 1))) {
213 return (unsigned int)interface->get_external_texture_for_eye(data, (godot_int)p_eye);
214 } else {
215 return 0;
216 }
217 }
218
commit_for_eye(ARVRInterface::Eyes p_eye,RID p_render_target,const Rect2 & p_screen_rect)219 void ARVRInterfaceGDNative::commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
220
221 ERR_FAIL_COND(interface == NULL);
222
223 interface->commit_for_eye(data, (godot_int)p_eye, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
224 }
225
process()226 void ARVRInterfaceGDNative::process() {
227 ERR_FAIL_COND(interface == NULL);
228
229 interface->process(data);
230 }
231
notification(int p_what)232 void ARVRInterfaceGDNative::notification(int p_what) {
233 ERR_FAIL_COND(interface == NULL);
234
235 // this is only available in interfaces that implement 1.1 or later
236 if ((interface->version.major > 1) || ((interface->version.major == 1) && (interface->version.minor > 0))) {
237 interface->notification(data, p_what);
238 }
239 }
240
241 /////////////////////////////////////////////////////////////////////////////////////
242 // some helper callbacks
243
244 extern "C" {
245
godot_arvr_register_interface(const godot_arvr_interface_gdnative * p_interface)246 void GDAPI godot_arvr_register_interface(const godot_arvr_interface_gdnative *p_interface) {
247 // If our major version is 0 or bigger then 10, we're likely looking at our constructor pointer from an older plugin
248 ERR_FAIL_COND_MSG((p_interface->version.major == 0) || (p_interface->version.major > 10), "GDNative ARVR interfaces build for Godot 3.0 are not supported.");
249
250 Ref<ARVRInterfaceGDNative> new_interface;
251 new_interface.instance();
252 new_interface->set_interface((const godot_arvr_interface_gdnative *)p_interface);
253 ARVRServer::get_singleton()->add_interface(new_interface);
254 }
255
godot_arvr_get_worldscale()256 godot_real GDAPI godot_arvr_get_worldscale() {
257 ARVRServer *arvr_server = ARVRServer::get_singleton();
258 ERR_FAIL_NULL_V(arvr_server, 1.0);
259
260 return arvr_server->get_world_scale();
261 }
262
godot_arvr_get_reference_frame()263 godot_transform GDAPI godot_arvr_get_reference_frame() {
264 godot_transform reference_frame;
265 Transform *reference_frame_ptr = (Transform *)&reference_frame;
266
267 ARVRServer *arvr_server = ARVRServer::get_singleton();
268 if (arvr_server != NULL) {
269 *reference_frame_ptr = arvr_server->get_reference_frame();
270 } else {
271 godot_transform_new_identity(&reference_frame);
272 }
273
274 return reference_frame;
275 }
276
godot_arvr_blit(godot_int p_eye,godot_rid * p_render_target,godot_rect2 * p_rect)277 void GDAPI godot_arvr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) {
278 // blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD
279 ARVRInterface::Eyes eye = (ARVRInterface::Eyes)p_eye;
280 RID *render_target = (RID *)p_render_target;
281 Rect2 screen_rect = *(Rect2 *)p_rect;
282
283 if (eye == ARVRInterface::EYE_LEFT) {
284 screen_rect.size.x /= 2.0;
285 } else if (p_eye == ARVRInterface::EYE_RIGHT) {
286 screen_rect.size.x /= 2.0;
287 screen_rect.position.x += screen_rect.size.x;
288 }
289
290 VSG::rasterizer->set_current_render_target(RID());
291 VSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0);
292 }
293
godot_arvr_get_texid(godot_rid * p_render_target)294 godot_int GDAPI godot_arvr_get_texid(godot_rid *p_render_target) {
295 // In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID
296 // This is a handy function to expose that.
297 RID *render_target = (RID *)p_render_target;
298
299 RID eye_texture = VSG::storage->render_target_get_texture(*render_target);
300 uint32_t texid = VS::get_singleton()->texture_get_texid(eye_texture);
301
302 return texid;
303 }
304
godot_arvr_add_controller(char * p_device_name,godot_int p_hand,godot_bool p_tracks_orientation,godot_bool p_tracks_position)305 godot_int GDAPI godot_arvr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
306 ARVRServer *arvr_server = ARVRServer::get_singleton();
307 ERR_FAIL_NULL_V(arvr_server, 0);
308
309 InputDefault *input = (InputDefault *)Input::get_singleton();
310 ERR_FAIL_NULL_V(input, 0);
311
312 ARVRPositionalTracker *new_tracker = memnew(ARVRPositionalTracker);
313 new_tracker->set_name(p_device_name);
314 new_tracker->set_type(ARVRServer::TRACKER_CONTROLLER);
315 if (p_hand == 1) {
316 new_tracker->set_hand(ARVRPositionalTracker::TRACKER_LEFT_HAND);
317 } else if (p_hand == 2) {
318 new_tracker->set_hand(ARVRPositionalTracker::TRACKER_RIGHT_HAND);
319 }
320
321 // also register as joystick...
322 int joyid = input->get_unused_joy_id();
323 if (joyid != -1) {
324 new_tracker->set_joy_id(joyid);
325 input->joy_connection_changed(joyid, true, p_device_name, "");
326 }
327
328 if (p_tracks_orientation) {
329 Basis orientation;
330 new_tracker->set_orientation(orientation);
331 }
332 if (p_tracks_position) {
333 Vector3 position;
334 new_tracker->set_position(position);
335 }
336
337 // add our tracker to our server and remember its pointer
338 arvr_server->add_tracker(new_tracker);
339
340 // note, this ID is only unique within controllers!
341 return new_tracker->get_tracker_id();
342 }
343
godot_arvr_remove_controller(godot_int p_controller_id)344 void GDAPI godot_arvr_remove_controller(godot_int p_controller_id) {
345 ARVRServer *arvr_server = ARVRServer::get_singleton();
346 ERR_FAIL_NULL(arvr_server);
347
348 InputDefault *input = (InputDefault *)Input::get_singleton();
349 ERR_FAIL_NULL(input);
350
351 ARVRPositionalTracker *remove_tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
352 if (remove_tracker != NULL) {
353 // unset our joystick if applicable
354 int joyid = remove_tracker->get_joy_id();
355 if (joyid != -1) {
356 input->joy_connection_changed(joyid, false, "", "");
357 remove_tracker->set_joy_id(-1);
358 }
359
360 // remove our tracker from our server
361 arvr_server->remove_tracker(remove_tracker);
362 memdelete(remove_tracker);
363 }
364 }
365
godot_arvr_set_controller_transform(godot_int p_controller_id,godot_transform * p_transform,godot_bool p_tracks_orientation,godot_bool p_tracks_position)366 void GDAPI godot_arvr_set_controller_transform(godot_int p_controller_id, godot_transform *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
367 ARVRServer *arvr_server = ARVRServer::get_singleton();
368 ERR_FAIL_NULL(arvr_server);
369
370 ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
371 if (tracker != NULL) {
372 Transform *transform = (Transform *)p_transform;
373 if (p_tracks_orientation) {
374 tracker->set_orientation(transform->basis);
375 }
376 if (p_tracks_position) {
377 tracker->set_rw_position(transform->origin);
378 }
379 }
380 }
381
godot_arvr_set_controller_button(godot_int p_controller_id,godot_int p_button,godot_bool p_is_pressed)382 void GDAPI godot_arvr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) {
383 ARVRServer *arvr_server = ARVRServer::get_singleton();
384 ERR_FAIL_NULL(arvr_server);
385
386 InputDefault *input = (InputDefault *)Input::get_singleton();
387 ERR_FAIL_NULL(input);
388
389 ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
390 if (tracker != NULL) {
391 int joyid = tracker->get_joy_id();
392 if (joyid != -1) {
393 input->joy_button(joyid, p_button, p_is_pressed);
394 }
395 }
396 }
397
godot_arvr_set_controller_axis(godot_int p_controller_id,godot_int p_axis,godot_real p_value,godot_bool p_can_be_negative)398 void GDAPI godot_arvr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real p_value, godot_bool p_can_be_negative) {
399 ARVRServer *arvr_server = ARVRServer::get_singleton();
400 ERR_FAIL_NULL(arvr_server);
401
402 InputDefault *input = (InputDefault *)Input::get_singleton();
403 ERR_FAIL_NULL(input);
404
405 ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
406 if (tracker != NULL) {
407 int joyid = tracker->get_joy_id();
408 if (joyid != -1) {
409 InputDefault::JoyAxis jx;
410 jx.min = p_can_be_negative ? -1 : 0;
411 jx.value = p_value;
412 input->joy_axis(joyid, p_axis, jx);
413 }
414 }
415 }
416
godot_arvr_get_controller_rumble(godot_int p_controller_id)417 godot_real GDAPI godot_arvr_get_controller_rumble(godot_int p_controller_id) {
418 ARVRServer *arvr_server = ARVRServer::get_singleton();
419 ERR_FAIL_NULL_V(arvr_server, 0.0);
420
421 ARVRPositionalTracker *tracker = arvr_server->find_by_type_and_id(ARVRServer::TRACKER_CONTROLLER, p_controller_id);
422 if (tracker != NULL) {
423 return tracker->get_rumble();
424 }
425
426 return 0.0;
427 }
428 }
429