1 /*************************************************************************/
2 /*  parallax_layer.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 "parallax_layer.h"
32 
33 #include "core/engine.h"
34 #include "parallax_background.h"
35 
set_motion_scale(const Size2 & p_scale)36 void ParallaxLayer::set_motion_scale(const Size2 &p_scale) {
37 
38 	motion_scale = p_scale;
39 
40 	ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
41 	if (pb && is_inside_tree()) {
42 		Vector2 ofs = pb->get_final_offset();
43 		float scale = pb->get_scroll_scale();
44 		set_base_offset_and_scale(ofs, scale, screen_offset);
45 	}
46 }
47 
get_motion_scale() const48 Size2 ParallaxLayer::get_motion_scale() const {
49 
50 	return motion_scale;
51 }
52 
set_motion_offset(const Size2 & p_offset)53 void ParallaxLayer::set_motion_offset(const Size2 &p_offset) {
54 
55 	motion_offset = p_offset;
56 
57 	ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
58 	if (pb && is_inside_tree()) {
59 		Vector2 ofs = pb->get_final_offset();
60 		float scale = pb->get_scroll_scale();
61 		set_base_offset_and_scale(ofs, scale, screen_offset);
62 	}
63 }
64 
get_motion_offset() const65 Size2 ParallaxLayer::get_motion_offset() const {
66 
67 	return motion_offset;
68 }
69 
_update_mirroring()70 void ParallaxLayer::_update_mirroring() {
71 
72 	if (!is_inside_tree())
73 		return;
74 
75 	ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
76 	if (pb) {
77 
78 		RID c = pb->get_canvas();
79 		RID ci = get_canvas_item();
80 		Point2 mirrorScale = mirroring * get_scale();
81 		VisualServer::get_singleton()->canvas_set_item_mirroring(c, ci, mirrorScale);
82 	}
83 }
84 
set_mirroring(const Size2 & p_mirroring)85 void ParallaxLayer::set_mirroring(const Size2 &p_mirroring) {
86 
87 	mirroring = p_mirroring;
88 	if (mirroring.x < 0)
89 		mirroring.x = 0;
90 	if (mirroring.y < 0)
91 		mirroring.y = 0;
92 
93 	_update_mirroring();
94 }
95 
get_mirroring() const96 Size2 ParallaxLayer::get_mirroring() const {
97 
98 	return mirroring;
99 }
100 
_notification(int p_what)101 void ParallaxLayer::_notification(int p_what) {
102 
103 	switch (p_what) {
104 
105 		case NOTIFICATION_ENTER_TREE: {
106 
107 			orig_offset = get_position();
108 			orig_scale = get_scale();
109 			_update_mirroring();
110 		} break;
111 		case NOTIFICATION_EXIT_TREE: {
112 
113 			set_position(orig_offset);
114 			set_scale(orig_scale);
115 		} break;
116 	}
117 }
118 
set_base_offset_and_scale(const Point2 & p_offset,float p_scale,const Point2 & p_screen_offset)119 void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_scale, const Point2 &p_screen_offset) {
120 	screen_offset = p_screen_offset;
121 
122 	if (!is_inside_tree())
123 		return;
124 	if (Engine::get_singleton()->is_editor_hint())
125 		return;
126 
127 	Point2 new_ofs = (screen_offset + (p_offset - screen_offset) * motion_scale) + motion_offset * p_scale + orig_offset * p_scale;
128 
129 	if (mirroring.x) {
130 		double den = mirroring.x * p_scale;
131 		new_ofs.x -= den * ceil(new_ofs.x / den);
132 	}
133 
134 	if (mirroring.y) {
135 		double den = mirroring.y * p_scale;
136 		new_ofs.y -= den * ceil(new_ofs.y / den);
137 	}
138 
139 	set_position(new_ofs);
140 	set_scale(Vector2(1, 1) * p_scale * orig_scale);
141 
142 	_update_mirroring();
143 }
144 
get_configuration_warning() const145 String ParallaxLayer::get_configuration_warning() const {
146 
147 	if (!Object::cast_to<ParallaxBackground>(get_parent())) {
148 		return TTR("ParallaxLayer node only works when set as child of a ParallaxBackground node.");
149 	}
150 
151 	return String();
152 }
153 
_bind_methods()154 void ParallaxLayer::_bind_methods() {
155 
156 	ClassDB::bind_method(D_METHOD("set_motion_scale", "scale"), &ParallaxLayer::set_motion_scale);
157 	ClassDB::bind_method(D_METHOD("get_motion_scale"), &ParallaxLayer::get_motion_scale);
158 	ClassDB::bind_method(D_METHOD("set_motion_offset", "offset"), &ParallaxLayer::set_motion_offset);
159 	ClassDB::bind_method(D_METHOD("get_motion_offset"), &ParallaxLayer::get_motion_offset);
160 	ClassDB::bind_method(D_METHOD("set_mirroring", "mirror"), &ParallaxLayer::set_mirroring);
161 	ClassDB::bind_method(D_METHOD("get_mirroring"), &ParallaxLayer::get_mirroring);
162 
163 	ADD_GROUP("Motion", "motion_");
164 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_scale"), "set_motion_scale", "get_motion_scale");
165 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_offset"), "set_motion_offset", "get_motion_offset");
166 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion_mirroring"), "set_mirroring", "get_mirroring");
167 }
168 
ParallaxLayer()169 ParallaxLayer::ParallaxLayer() {
170 	motion_scale = Size2(1, 1);
171 }
172