Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/scene/2d/parallax_2d.cpp
9902 views
1
/**************************************************************************/
2
/* parallax_2d.cpp */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
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 "parallax_2d.h"
32
33
#include "scene/main/viewport.h"
34
35
void Parallax2D::_notification(int p_what) {
36
switch (p_what) {
37
case NOTIFICATION_ENTER_TREE: {
38
group_name = "__cameras_" + itos(get_viewport_rid().get_id());
39
add_to_group(group_name);
40
_update_repeat();
41
_update_scroll();
42
} break;
43
44
case NOTIFICATION_READY: {
45
_update_process();
46
} break;
47
48
case NOTIFICATION_INTERNAL_PROCESS: {
49
Point2 offset = scroll_offset;
50
offset += autoscroll * get_process_delta_time();
51
52
if (repeat_size.x) {
53
offset.x = Math::fposmod(offset.x, repeat_size.x);
54
}
55
56
if (repeat_size.y) {
57
offset.y = Math::fposmod(offset.y, repeat_size.y);
58
}
59
60
scroll_offset = offset;
61
_update_scroll();
62
} break;
63
64
case NOTIFICATION_EXIT_TREE: {
65
remove_from_group(group_name);
66
} break;
67
}
68
}
69
70
#ifdef TOOLS_ENABLED
71
void Parallax2D::_edit_set_position(const Point2 &p_position) {
72
// Avoids early return for grid snap compatibility
73
scroll_offset = p_position;
74
_update_scroll();
75
}
76
#endif // TOOLS_ENABLED
77
78
void Parallax2D::_validate_property(PropertyInfo &p_property) const {
79
if (p_property.name == "position") {
80
p_property.usage = PROPERTY_USAGE_NONE;
81
}
82
}
83
84
void Parallax2D::_camera_moved(const Transform2D &p_transform, const Point2 &p_screen_offset, const Point2 &p_adj_screen_pos) {
85
if (!ignore_camera_scroll) {
86
if (get_viewport() && get_viewport()->is_snap_2d_transforms_to_pixel_enabled()) {
87
Size2 vps = get_viewport_rect().size;
88
Vector2 offset;
89
offset.x = ((int)vps.width % 2) ? 0.0 : 0.5;
90
offset.y = ((int)vps.height % 2) ? 0.0 : 0.5;
91
set_screen_offset((p_adj_screen_pos + offset).floor());
92
} else {
93
set_screen_offset(p_adj_screen_pos);
94
}
95
}
96
}
97
98
void Parallax2D::_update_process() {
99
set_process_internal(!Engine::get_singleton()->is_editor_hint() && (repeat_size.x || repeat_size.y) && (autoscroll.x || autoscroll.y));
100
}
101
102
void Parallax2D::_update_scroll() {
103
if (!is_inside_tree()) {
104
return;
105
}
106
107
Point2 scroll_ofs = screen_offset;
108
109
if (!Engine::get_singleton()->is_editor_hint()) {
110
Size2 vps = get_viewport_rect().size;
111
112
if (limit_begin.x <= limit_end.x - vps.x) {
113
scroll_ofs.x = CLAMP(scroll_ofs.x, limit_begin.x, limit_end.x - vps.x);
114
}
115
if (limit_begin.y <= limit_end.y - vps.y) {
116
scroll_ofs.y = CLAMP(scroll_ofs.y, limit_begin.y, limit_end.y - vps.y);
117
}
118
}
119
120
scroll_ofs *= scroll_scale;
121
122
if (repeat_size.x) {
123
real_t mod = Math::fposmod(scroll_ofs.x - scroll_offset.x, repeat_size.x * get_scale().x);
124
scroll_ofs.x = screen_offset.x - mod;
125
} else {
126
scroll_ofs.x = screen_offset.x + scroll_offset.x - scroll_ofs.x;
127
}
128
129
if (repeat_size.y) {
130
real_t mod = Math::fposmod(scroll_ofs.y - scroll_offset.y, repeat_size.y * get_scale().y);
131
scroll_ofs.y = screen_offset.y - mod;
132
} else {
133
scroll_ofs.y = screen_offset.y + scroll_offset.y - scroll_ofs.y;
134
}
135
136
if (!follow_viewport) {
137
scroll_ofs -= screen_offset;
138
}
139
140
set_position(scroll_ofs);
141
}
142
143
void Parallax2D::_update_repeat() {
144
if (!is_inside_tree()) {
145
return;
146
}
147
148
RenderingServer::get_singleton()->canvas_set_item_repeat(get_canvas_item(), repeat_size, repeat_times);
149
RenderingServer::get_singleton()->canvas_item_set_interpolated(get_canvas_item(), false);
150
}
151
152
void Parallax2D::set_scroll_scale(const Size2 &p_scale) {
153
scroll_scale = p_scale;
154
}
155
156
Size2 Parallax2D::get_scroll_scale() const {
157
return scroll_scale;
158
}
159
160
void Parallax2D::set_repeat_size(const Size2 &p_repeat_size) {
161
if (p_repeat_size == repeat_size) {
162
return;
163
}
164
165
repeat_size = p_repeat_size.maxf(0);
166
167
_update_process();
168
_update_repeat();
169
_update_scroll();
170
}
171
172
Size2 Parallax2D::get_repeat_size() const {
173
return repeat_size;
174
}
175
176
void Parallax2D::set_repeat_times(int p_repeat_times) {
177
if (p_repeat_times == repeat_times) {
178
return;
179
}
180
181
repeat_times = MAX(p_repeat_times, 1);
182
183
_update_repeat();
184
}
185
186
int Parallax2D::get_repeat_times() const {
187
return repeat_times;
188
}
189
190
void Parallax2D::set_scroll_offset(const Point2 &p_offset) {
191
if (p_offset == scroll_offset) {
192
return;
193
}
194
195
scroll_offset = p_offset;
196
197
_update_scroll();
198
}
199
200
Point2 Parallax2D::get_scroll_offset() const {
201
return scroll_offset;
202
}
203
204
void Parallax2D::set_autoscroll(const Point2 &p_autoscroll) {
205
if (p_autoscroll == autoscroll) {
206
return;
207
}
208
209
autoscroll = p_autoscroll;
210
211
_update_process();
212
_update_scroll();
213
}
214
215
Point2 Parallax2D::get_autoscroll() const {
216
return autoscroll;
217
}
218
219
void Parallax2D::set_screen_offset(const Point2 &p_offset) {
220
if (p_offset == screen_offset) {
221
return;
222
}
223
224
screen_offset = p_offset;
225
226
_update_scroll();
227
}
228
229
Point2 Parallax2D::get_screen_offset() const {
230
return screen_offset;
231
}
232
233
void Parallax2D::set_limit_begin(const Point2 &p_offset) {
234
limit_begin = p_offset;
235
}
236
237
Point2 Parallax2D::get_limit_begin() const {
238
return limit_begin;
239
}
240
241
void Parallax2D::set_limit_end(const Point2 &p_offset) {
242
limit_end = p_offset;
243
}
244
245
Point2 Parallax2D::get_limit_end() const {
246
return limit_end;
247
}
248
249
void Parallax2D::set_follow_viewport(bool p_follow) {
250
follow_viewport = p_follow;
251
}
252
253
bool Parallax2D::get_follow_viewport() {
254
return follow_viewport;
255
}
256
257
void Parallax2D::set_ignore_camera_scroll(bool p_ignore) {
258
ignore_camera_scroll = p_ignore;
259
}
260
261
bool Parallax2D::is_ignore_camera_scroll() {
262
return ignore_camera_scroll;
263
}
264
265
void Parallax2D::_bind_methods() {
266
ClassDB::bind_method(D_METHOD("_camera_moved", "transform", "screen_offset", "adj_screen_offset"), &Parallax2D::_camera_moved);
267
ClassDB::bind_method(D_METHOD("set_scroll_scale", "scale"), &Parallax2D::set_scroll_scale);
268
ClassDB::bind_method(D_METHOD("get_scroll_scale"), &Parallax2D::get_scroll_scale);
269
ClassDB::bind_method(D_METHOD("set_repeat_size", "repeat_size"), &Parallax2D::set_repeat_size);
270
ClassDB::bind_method(D_METHOD("get_repeat_size"), &Parallax2D::get_repeat_size);
271
ClassDB::bind_method(D_METHOD("set_repeat_times", "repeat_times"), &Parallax2D::set_repeat_times);
272
ClassDB::bind_method(D_METHOD("get_repeat_times"), &Parallax2D::get_repeat_times);
273
ClassDB::bind_method(D_METHOD("set_autoscroll", "autoscroll"), &Parallax2D::set_autoscroll);
274
ClassDB::bind_method(D_METHOD("get_autoscroll"), &Parallax2D::get_autoscroll);
275
ClassDB::bind_method(D_METHOD("set_scroll_offset", "offset"), &Parallax2D::set_scroll_offset);
276
ClassDB::bind_method(D_METHOD("get_scroll_offset"), &Parallax2D::get_scroll_offset);
277
ClassDB::bind_method(D_METHOD("set_screen_offset", "offset"), &Parallax2D::set_screen_offset);
278
ClassDB::bind_method(D_METHOD("get_screen_offset"), &Parallax2D::get_screen_offset);
279
ClassDB::bind_method(D_METHOD("set_limit_begin", "offset"), &Parallax2D::set_limit_begin);
280
ClassDB::bind_method(D_METHOD("get_limit_begin"), &Parallax2D::get_limit_begin);
281
ClassDB::bind_method(D_METHOD("set_limit_end", "offset"), &Parallax2D::set_limit_end);
282
ClassDB::bind_method(D_METHOD("get_limit_end"), &Parallax2D::get_limit_end);
283
ClassDB::bind_method(D_METHOD("set_follow_viewport", "follow"), &Parallax2D::set_follow_viewport);
284
ClassDB::bind_method(D_METHOD("get_follow_viewport"), &Parallax2D::get_follow_viewport);
285
ClassDB::bind_method(D_METHOD("set_ignore_camera_scroll", "ignore"), &Parallax2D::set_ignore_camera_scroll);
286
ClassDB::bind_method(D_METHOD("is_ignore_camera_scroll"), &Parallax2D::is_ignore_camera_scroll);
287
288
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_scale", PROPERTY_HINT_LINK), "set_scroll_scale", "get_scroll_scale");
289
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_scroll_offset", "get_scroll_offset");
290
291
ADD_GROUP("Repeat", "");
292
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "repeat_size"), "set_repeat_size", "get_repeat_size");
293
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "autoscroll", PROPERTY_HINT_NONE, "suffix:px/s"), "set_autoscroll", "get_autoscroll");
294
ADD_PROPERTY(PropertyInfo(Variant::INT, "repeat_times"), "set_repeat_times", "get_repeat_times");
295
296
ADD_GROUP("Limit", "limit_");
297
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "limit_begin", PROPERTY_HINT_NONE, "suffix:px"), "set_limit_begin", "get_limit_begin");
298
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "limit_end", PROPERTY_HINT_NONE, "suffix:px"), "set_limit_end", "get_limit_end");
299
300
ADD_GROUP("Override", "");
301
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "follow_viewport"), "set_follow_viewport", "get_follow_viewport");
302
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ignore_camera_scroll"), "set_ignore_camera_scroll", "is_ignore_camera_scroll");
303
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "screen_offset", PROPERTY_HINT_NONE, "suffix:px"), "set_screen_offset", "get_screen_offset");
304
}
305
306
Parallax2D::Parallax2D() {
307
// Parallax2D is always updated every frame so there is no need to interpolate.
308
set_physics_interpolation_mode(Node::PHYSICS_INTERPOLATION_MODE_OFF);
309
}
310
311