1 /*************************************************************************/
2 /*  light_occluder_2d.cpp                                                */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 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 #include "light_occluder_2d.h"
31 
set_polygon(const DVector<Vector2> & p_polygon)32 void OccluderPolygon2D::set_polygon(const DVector<Vector2> &p_polygon) {
33 
34 	polygon = p_polygon;
35 	VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, p_polygon, closed);
36 	emit_changed();
37 }
38 
get_polygon() const39 DVector<Vector2> OccluderPolygon2D::get_polygon() const {
40 
41 	return polygon;
42 }
43 
set_closed(bool p_closed)44 void OccluderPolygon2D::set_closed(bool p_closed) {
45 
46 	if (closed == p_closed)
47 		return;
48 	closed = p_closed;
49 	if (polygon.size())
50 		VS::get_singleton()->canvas_occluder_polygon_set_shape(occ_polygon, polygon, closed);
51 	emit_changed();
52 }
53 
is_closed() const54 bool OccluderPolygon2D::is_closed() const {
55 
56 	return closed;
57 }
58 
set_cull_mode(CullMode p_mode)59 void OccluderPolygon2D::set_cull_mode(CullMode p_mode) {
60 
61 	cull = p_mode;
62 	VS::get_singleton()->canvas_occluder_polygon_set_cull_mode(occ_polygon, VS::CanvasOccluderPolygonCullMode(p_mode));
63 }
64 
get_cull_mode() const65 OccluderPolygon2D::CullMode OccluderPolygon2D::get_cull_mode() const {
66 
67 	return cull;
68 }
69 
get_rid() const70 RID OccluderPolygon2D::get_rid() const {
71 
72 	return occ_polygon;
73 }
74 
_bind_methods()75 void OccluderPolygon2D::_bind_methods() {
76 
77 	ObjectTypeDB::bind_method(_MD("set_closed", "closed"), &OccluderPolygon2D::set_closed);
78 	ObjectTypeDB::bind_method(_MD("is_closed"), &OccluderPolygon2D::is_closed);
79 
80 	ObjectTypeDB::bind_method(_MD("set_cull_mode", "cull_mode"), &OccluderPolygon2D::set_cull_mode);
81 	ObjectTypeDB::bind_method(_MD("get_cull_mode"), &OccluderPolygon2D::get_cull_mode);
82 
83 	ObjectTypeDB::bind_method(_MD("set_polygon", "polygon"), &OccluderPolygon2D::set_polygon);
84 	ObjectTypeDB::bind_method(_MD("get_polygon"), &OccluderPolygon2D::get_polygon);
85 
86 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "closed"), _SCS("set_closed"), _SCS("is_closed"));
87 	ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mode", PROPERTY_HINT_ENUM, "Disabled,ClockWise,CounterClockWise"), _SCS("set_cull_mode"), _SCS("get_cull_mode"));
88 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY, "polygon"), _SCS("set_polygon"), _SCS("get_polygon"));
89 
90 	BIND_CONSTANT(CULL_DISABLED);
91 	BIND_CONSTANT(CULL_CLOCKWISE);
92 	BIND_CONSTANT(CULL_COUNTER_CLOCKWISE);
93 }
94 
OccluderPolygon2D()95 OccluderPolygon2D::OccluderPolygon2D() {
96 
97 	occ_polygon = VS::get_singleton()->canvas_occluder_polygon_create();
98 	closed = true;
99 	cull = CULL_DISABLED;
100 }
101 
~OccluderPolygon2D()102 OccluderPolygon2D::~OccluderPolygon2D() {
103 
104 	VS::get_singleton()->free(occ_polygon);
105 }
106 
107 #ifdef DEBUG_ENABLED
_poly_changed()108 void LightOccluder2D::_poly_changed() {
109 
110 	update();
111 }
112 #endif
113 
_notification(int p_what)114 void LightOccluder2D::_notification(int p_what) {
115 
116 	if (p_what == NOTIFICATION_ENTER_CANVAS) {
117 
118 		VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, get_canvas());
119 		VS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
120 		VS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible());
121 	}
122 	if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
123 
124 		VS::get_singleton()->canvas_light_occluder_set_transform(occluder, get_global_transform());
125 	}
126 	if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
127 
128 		VS::get_singleton()->canvas_light_occluder_set_enabled(occluder, is_visible());
129 	}
130 
131 	if (p_what == NOTIFICATION_DRAW) {
132 
133 		if (get_tree()->is_editor_hint()) {
134 
135 			if (occluder_polygon.is_valid()) {
136 
137 				DVector<Vector2> poly = occluder_polygon->get_polygon();
138 
139 				if (poly.size()) {
140 					if (occluder_polygon->is_closed()) {
141 						Vector<Color> color;
142 						color.push_back(Color(0, 0, 0, 0.6));
143 						draw_polygon(Variant(poly), color);
144 					} else {
145 
146 						int ps = poly.size();
147 						DVector<Vector2>::Read r = poly.read();
148 						for (int i = 0; i < ps - 1; i++) {
149 
150 							draw_line(r[i], r[i + 1], Color(0, 0, 0, 0.6), 3);
151 						}
152 					}
153 				}
154 			}
155 		}
156 	}
157 
158 	if (p_what == NOTIFICATION_EXIT_CANVAS) {
159 
160 		VS::get_singleton()->canvas_light_occluder_attach_to_canvas(occluder, RID());
161 	}
162 }
163 
set_occluder_polygon(const Ref<OccluderPolygon2D> & p_polygon)164 void LightOccluder2D::set_occluder_polygon(const Ref<OccluderPolygon2D> &p_polygon) {
165 
166 #ifdef DEBUG_ENABLED
167 	if (occluder_polygon.is_valid())
168 		occluder_polygon->disconnect("changed", this, "_poly_changed");
169 #endif
170 	occluder_polygon = p_polygon;
171 
172 	if (occluder_polygon.is_valid())
173 		VS::get_singleton()->canvas_light_occluder_set_polygon(occluder, occluder_polygon->get_rid());
174 	else
175 		VS::get_singleton()->canvas_light_occluder_set_polygon(occluder, RID());
176 
177 #ifdef DEBUG_ENABLED
178 	if (occluder_polygon.is_valid())
179 		occluder_polygon->connect("changed", this, "_poly_changed");
180 	update();
181 #endif
182 }
183 
get_occluder_polygon() const184 Ref<OccluderPolygon2D> LightOccluder2D::get_occluder_polygon() const {
185 
186 	return occluder_polygon;
187 }
188 
set_occluder_light_mask(int p_mask)189 void LightOccluder2D::set_occluder_light_mask(int p_mask) {
190 
191 	mask = p_mask;
192 	VS::get_singleton()->canvas_light_occluder_set_light_mask(occluder, mask);
193 }
194 
get_occluder_light_mask() const195 int LightOccluder2D::get_occluder_light_mask() const {
196 
197 	return mask;
198 }
199 
get_configuration_warning() const200 String LightOccluder2D::get_configuration_warning() const {
201 
202 	if (!occluder_polygon.is_valid()) {
203 		return TTR("An occluder polygon must be set (or drawn) for this occluder to take effect.");
204 	}
205 
206 	if (occluder_polygon.is_valid() && occluder_polygon->get_polygon().size() == 0) {
207 		return TTR("The occluder polygon for this occluder is empty. Please draw a polygon!");
208 	}
209 
210 	return String();
211 }
212 
_bind_methods()213 void LightOccluder2D::_bind_methods() {
214 
215 	ObjectTypeDB::bind_method(_MD("set_occluder_polygon", "polygon:OccluderPolygon2D"), &LightOccluder2D::set_occluder_polygon);
216 	ObjectTypeDB::bind_method(_MD("get_occluder_polygon:OccluderPolygon2D"), &LightOccluder2D::get_occluder_polygon);
217 
218 	ObjectTypeDB::bind_method(_MD("set_occluder_light_mask", "mask"), &LightOccluder2D::set_occluder_light_mask);
219 	ObjectTypeDB::bind_method(_MD("get_occluder_light_mask"), &LightOccluder2D::get_occluder_light_mask);
220 
221 #ifdef DEBUG_ENABLED
222 	ObjectTypeDB::bind_method("_poly_changed", &LightOccluder2D::_poly_changed);
223 #endif
224 
225 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"), _SCS("set_occluder_polygon"), _SCS("get_occluder_polygon"));
226 	ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_ALL_FLAGS), _SCS("set_occluder_light_mask"), _SCS("get_occluder_light_mask"));
227 }
228 
LightOccluder2D()229 LightOccluder2D::LightOccluder2D() {
230 
231 	occluder = VS::get_singleton()->canvas_light_occluder_create();
232 	mask = 1;
233 }
234 
~LightOccluder2D()235 LightOccluder2D::~LightOccluder2D() {
236 
237 	VS::get_singleton()->free(occluder);
238 }
239