1 /*************************************************************************/
2 /* remote_transform.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 "remote_transform.h"
32
_update_cache()33 void RemoteTransform::_update_cache() {
34 cache = 0;
35 if (has_node(remote_node)) {
36 Node *node = get_node(remote_node);
37 if (!node || this == node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) {
38 return;
39 }
40
41 cache = node->get_instance_id();
42 }
43 }
44
_update_remote()45 void RemoteTransform::_update_remote() {
46
47 if (!is_inside_tree())
48 return;
49
50 if (!cache)
51 return;
52
53 Spatial *n = Object::cast_to<Spatial>(ObjectDB::get_instance(cache));
54 if (!n)
55 return;
56
57 if (!n->is_inside_tree())
58 return;
59
60 //todo make faster
61 if (use_global_coordinates) {
62
63 if (update_remote_position && update_remote_rotation && update_remote_scale) {
64 n->set_global_transform(get_global_transform());
65 } else {
66 Transform our_trans = get_global_transform();
67
68 if (update_remote_rotation)
69 n->set_rotation(our_trans.basis.get_rotation());
70
71 if (update_remote_scale)
72 n->set_scale(our_trans.basis.get_scale());
73
74 if (update_remote_position) {
75 Transform n_trans = n->get_global_transform();
76
77 n_trans.set_origin(our_trans.get_origin());
78 n->set_global_transform(n_trans);
79 }
80 }
81
82 } else {
83 if (update_remote_position && update_remote_rotation && update_remote_scale) {
84 n->set_transform(get_transform());
85 } else {
86 Transform our_trans = get_transform();
87
88 if (update_remote_rotation)
89 n->set_rotation(our_trans.basis.get_rotation());
90
91 if (update_remote_scale)
92 n->set_scale(our_trans.basis.get_scale());
93
94 if (update_remote_position) {
95 Transform n_trans = n->get_transform();
96
97 n_trans.set_origin(our_trans.get_origin());
98 n->set_transform(n_trans);
99 }
100 }
101 }
102 }
103
_notification(int p_what)104 void RemoteTransform::_notification(int p_what) {
105
106 switch (p_what) {
107
108 case NOTIFICATION_ENTER_TREE: {
109
110 _update_cache();
111
112 } break;
113 case NOTIFICATION_TRANSFORM_CHANGED: {
114 if (!is_inside_tree())
115 break;
116
117 if (cache) {
118
119 _update_remote();
120 }
121
122 } break;
123 }
124 }
125
set_remote_node(const NodePath & p_remote_node)126 void RemoteTransform::set_remote_node(const NodePath &p_remote_node) {
127
128 remote_node = p_remote_node;
129 if (is_inside_tree()) {
130 _update_cache();
131 _update_remote();
132 }
133
134 update_configuration_warning();
135 }
136
get_remote_node() const137 NodePath RemoteTransform::get_remote_node() const {
138
139 return remote_node;
140 }
141
set_use_global_coordinates(const bool p_enable)142 void RemoteTransform::set_use_global_coordinates(const bool p_enable) {
143 use_global_coordinates = p_enable;
144 }
145
get_use_global_coordinates() const146 bool RemoteTransform::get_use_global_coordinates() const {
147 return use_global_coordinates;
148 }
149
set_update_position(const bool p_update)150 void RemoteTransform::set_update_position(const bool p_update) {
151 update_remote_position = p_update;
152 _update_remote();
153 }
154
get_update_position() const155 bool RemoteTransform::get_update_position() const {
156 return update_remote_position;
157 }
158
set_update_rotation(const bool p_update)159 void RemoteTransform::set_update_rotation(const bool p_update) {
160 update_remote_rotation = p_update;
161 _update_remote();
162 }
163
get_update_rotation() const164 bool RemoteTransform::get_update_rotation() const {
165 return update_remote_rotation;
166 }
167
set_update_scale(const bool p_update)168 void RemoteTransform::set_update_scale(const bool p_update) {
169 update_remote_scale = p_update;
170 _update_remote();
171 }
172
get_update_scale() const173 bool RemoteTransform::get_update_scale() const {
174 return update_remote_scale;
175 }
176
force_update_cache()177 void RemoteTransform::force_update_cache() {
178 _update_cache();
179 }
180
get_configuration_warning() const181 String RemoteTransform::get_configuration_warning() const {
182
183 if (!has_node(remote_node) || !Object::cast_to<Spatial>(get_node(remote_node))) {
184 return TTR("The \"Remote Path\" property must point to a valid Spatial or Spatial-derived node to work.");
185 }
186
187 return String();
188 }
189
_bind_methods()190 void RemoteTransform::_bind_methods() {
191
192 ClassDB::bind_method(D_METHOD("set_remote_node", "path"), &RemoteTransform::set_remote_node);
193 ClassDB::bind_method(D_METHOD("get_remote_node"), &RemoteTransform::get_remote_node);
194 ClassDB::bind_method(D_METHOD("force_update_cache"), &RemoteTransform::force_update_cache);
195
196 ClassDB::bind_method(D_METHOD("set_use_global_coordinates", "use_global_coordinates"), &RemoteTransform::set_use_global_coordinates);
197 ClassDB::bind_method(D_METHOD("get_use_global_coordinates"), &RemoteTransform::get_use_global_coordinates);
198
199 ClassDB::bind_method(D_METHOD("set_update_position", "update_remote_position"), &RemoteTransform::set_update_position);
200 ClassDB::bind_method(D_METHOD("get_update_position"), &RemoteTransform::get_update_position);
201 ClassDB::bind_method(D_METHOD("set_update_rotation", "update_remote_rotation"), &RemoteTransform::set_update_rotation);
202 ClassDB::bind_method(D_METHOD("get_update_rotation"), &RemoteTransform::get_update_rotation);
203 ClassDB::bind_method(D_METHOD("set_update_scale", "update_remote_scale"), &RemoteTransform::set_update_scale);
204 ClassDB::bind_method(D_METHOD("get_update_scale"), &RemoteTransform::get_update_scale);
205
206 ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "remote_path", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Spatial"), "set_remote_node", "get_remote_node");
207 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_global_coordinates"), "set_use_global_coordinates", "get_use_global_coordinates");
208
209 ADD_GROUP("Update", "update_");
210 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_position"), "set_update_position", "get_update_position");
211 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_rotation"), "set_update_rotation", "get_update_rotation");
212 ADD_PROPERTY(PropertyInfo(Variant::BOOL, "update_scale"), "set_update_scale", "get_update_scale");
213 }
214
RemoteTransform()215 RemoteTransform::RemoteTransform() {
216
217 use_global_coordinates = true;
218 update_remote_position = true;
219 update_remote_rotation = true;
220 update_remote_scale = true;
221
222 cache = 0;
223 set_notify_transform(true);
224 }
225