1 /*************************************************************************/
2 /*  polygon_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 "polygon_2d.h"
31 
get_item_rect() const32 Rect2 Polygon2D::get_item_rect() const {
33 
34 	if (rect_cache_dirty) {
35 		int l = polygon.size();
36 		DVector<Vector2>::Read r = polygon.read();
37 		item_rect = Rect2();
38 		for (int i = 0; i < l; i++) {
39 			Vector2 pos = r[i] + offset;
40 			if (i == 0)
41 				item_rect.pos = pos;
42 			else
43 				item_rect.expand_to(pos);
44 		}
45 		item_rect = item_rect.grow(20);
46 		rect_cache_dirty = false;
47 	}
48 
49 	return item_rect;
50 }
51 
edit_set_pivot(const Point2 & p_pivot)52 void Polygon2D::edit_set_pivot(const Point2 &p_pivot) {
53 
54 	set_offset(p_pivot);
55 }
56 
edit_get_pivot() const57 Point2 Polygon2D::edit_get_pivot() const {
58 
59 	return get_offset();
60 }
edit_has_pivot() const61 bool Polygon2D::edit_has_pivot() const {
62 
63 	return true;
64 }
65 
_notification(int p_what)66 void Polygon2D::_notification(int p_what) {
67 
68 	switch (p_what) {
69 
70 		case NOTIFICATION_DRAW: {
71 
72 			if (polygon.size() < 3)
73 				return;
74 
75 			Vector<Vector2> points;
76 			Vector<Vector2> uvs;
77 
78 			points.resize(polygon.size());
79 
80 			int len = points.size();
81 			{
82 
83 				DVector<Vector2>::Read polyr = polygon.read();
84 				for (int i = 0; i < len; i++) {
85 					points[i] = polyr[i] + offset;
86 				}
87 			}
88 
89 			if (invert) {
90 
91 				Rect2 bounds;
92 				int highest_idx = -1;
93 				float highest_y = -1e20;
94 				float sum = 0;
95 
96 				for (int i = 0; i < len; i++) {
97 					if (i == 0)
98 						bounds.pos = points[i];
99 					else
100 						bounds.expand_to(points[i]);
101 					if (points[i].y > highest_y) {
102 						highest_idx = i;
103 						highest_y = points[i].y;
104 					}
105 					int ni = (i + 1) % len;
106 					sum += (points[ni].x - points[i].x) * (points[ni].y + points[i].y);
107 				}
108 
109 				bounds = bounds.grow(invert_border);
110 
111 				Vector2 ep[7] = {
112 					Vector2(points[highest_idx].x, points[highest_idx].y + invert_border),
113 					Vector2(bounds.pos + bounds.size),
114 					Vector2(bounds.pos + Vector2(bounds.size.x, 0)),
115 					Vector2(bounds.pos),
116 					Vector2(bounds.pos + Vector2(0, bounds.size.y)),
117 					Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y + invert_border),
118 					Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y),
119 				};
120 
121 				if (sum > 0) {
122 					SWAP(ep[1], ep[4]);
123 					SWAP(ep[2], ep[3]);
124 					SWAP(ep[5], ep[0]);
125 					SWAP(ep[6], points[highest_idx]);
126 				}
127 
128 				points.resize(points.size() + 7);
129 				for (int i = points.size() - 1; i >= highest_idx + 7; i--) {
130 
131 					points[i] = points[i - 7];
132 				}
133 
134 				for (int i = 0; i < 7; i++) {
135 
136 					points[highest_idx + i + 1] = ep[i];
137 				}
138 
139 				len = points.size();
140 			}
141 
142 			if (texture.is_valid()) {
143 
144 				Matrix32 texmat(tex_rot, tex_ofs);
145 				texmat.scale(tex_scale);
146 				Size2 tex_size = Vector2(1, 1);
147 
148 				tex_size = texture->get_size();
149 				uvs.resize(points.size());
150 
151 				if (points.size() == uv.size()) {
152 
153 					DVector<Vector2>::Read uvr = uv.read();
154 
155 					for (int i = 0; i < len; i++) {
156 						uvs[i] = texmat.xform(uvr[i]) / tex_size;
157 					}
158 
159 				} else {
160 					for (int i = 0; i < len; i++) {
161 						uvs[i] = texmat.xform(points[i]) / tex_size;
162 					}
163 				}
164 			}
165 
166 			Vector<Color> colors;
167 			int color_len = vertex_colors.size();
168 			if (color_len == 0) {
169 				// No vertex colors => Pass only the main color
170 				// The rasterizer handles this case especially, taking alpha into account
171 				colors.push_back(color);
172 			} else {
173 				// Vertex colors present => Fill color array and pad with main color as necessary
174 				colors.resize(len);
175 				DVector<Color>::Read color_r = vertex_colors.read();
176 				for (int i = 0; i < color_len && i < len; i++) {
177 					colors[i] = color_r[i];
178 				}
179 				for (int i = color_len; i < len; i++) {
180 					colors[i] = color;
181 				}
182 			}
183 
184 			Vector<int> indices = Geometry::triangulate_polygon(points);
185 
186 			VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID());
187 
188 		} break;
189 	}
190 }
191 
set_polygon(const DVector<Vector2> & p_polygon)192 void Polygon2D::set_polygon(const DVector<Vector2> &p_polygon) {
193 	polygon = p_polygon;
194 	rect_cache_dirty = true;
195 	update();
196 }
197 
get_polygon() const198 DVector<Vector2> Polygon2D::get_polygon() const {
199 
200 	return polygon;
201 }
202 
set_uv(const DVector<Vector2> & p_uv)203 void Polygon2D::set_uv(const DVector<Vector2> &p_uv) {
204 
205 	uv = p_uv;
206 	update();
207 }
208 
get_uv() const209 DVector<Vector2> Polygon2D::get_uv() const {
210 
211 	return uv;
212 }
213 
set_color(const Color & p_color)214 void Polygon2D::set_color(const Color &p_color) {
215 
216 	color = p_color;
217 	update();
218 }
get_color() const219 Color Polygon2D::get_color() const {
220 
221 	return color;
222 }
223 
set_vertex_colors(const DVector<Color> & p_colors)224 void Polygon2D::set_vertex_colors(const DVector<Color> &p_colors) {
225 
226 	vertex_colors = p_colors;
227 	update();
228 }
get_vertex_colors() const229 DVector<Color> Polygon2D::get_vertex_colors() const {
230 
231 	return vertex_colors;
232 }
233 
set_texture(const Ref<Texture> & p_texture)234 void Polygon2D::set_texture(const Ref<Texture> &p_texture) {
235 
236 	texture = p_texture;
237 
238 	/*if (texture.is_valid()) {
239 		uint32_t flags=texture->get_flags();
240 		flags&=~Texture::FLAG_REPEAT;
241 		if (tex_tile)
242 			flags|=Texture::FLAG_REPEAT;
243 
244 		texture->set_flags(flags);
245 	}*/
246 	update();
247 }
get_texture() const248 Ref<Texture> Polygon2D::get_texture() const {
249 
250 	return texture;
251 }
252 
set_texture_offset(const Vector2 & p_offset)253 void Polygon2D::set_texture_offset(const Vector2 &p_offset) {
254 
255 	tex_ofs = p_offset;
256 	update();
257 }
get_texture_offset() const258 Vector2 Polygon2D::get_texture_offset() const {
259 
260 	return tex_ofs;
261 }
262 
set_texture_rotation(float p_rot)263 void Polygon2D::set_texture_rotation(float p_rot) {
264 
265 	tex_rot = p_rot;
266 	update();
267 }
get_texture_rotation() const268 float Polygon2D::get_texture_rotation() const {
269 
270 	return tex_rot;
271 }
272 
_set_texture_rotationd(float p_rot)273 void Polygon2D::_set_texture_rotationd(float p_rot) {
274 
275 	set_texture_rotation(Math::deg2rad(p_rot));
276 }
_get_texture_rotationd() const277 float Polygon2D::_get_texture_rotationd() const {
278 
279 	return Math::rad2deg(get_texture_rotation());
280 }
281 
set_texture_scale(const Size2 & p_scale)282 void Polygon2D::set_texture_scale(const Size2 &p_scale) {
283 
284 	tex_scale = p_scale;
285 	update();
286 }
get_texture_scale() const287 Size2 Polygon2D::get_texture_scale() const {
288 
289 	return tex_scale;
290 }
291 
set_invert(bool p_invert)292 void Polygon2D::set_invert(bool p_invert) {
293 
294 	invert = p_invert;
295 	update();
296 }
get_invert() const297 bool Polygon2D::get_invert() const {
298 
299 	return invert;
300 }
301 
set_invert_border(float p_invert_border)302 void Polygon2D::set_invert_border(float p_invert_border) {
303 
304 	invert_border = p_invert_border;
305 	update();
306 }
get_invert_border() const307 float Polygon2D::get_invert_border() const {
308 
309 	return invert_border;
310 }
311 
set_offset(const Vector2 & p_offset)312 void Polygon2D::set_offset(const Vector2 &p_offset) {
313 
314 	offset = p_offset;
315 	rect_cache_dirty = true;
316 	update();
317 }
318 
get_offset() const319 Vector2 Polygon2D::get_offset() const {
320 
321 	return offset;
322 }
323 
_bind_methods()324 void Polygon2D::_bind_methods() {
325 
326 	ObjectTypeDB::bind_method(_MD("set_polygon", "polygon"), &Polygon2D::set_polygon);
327 	ObjectTypeDB::bind_method(_MD("get_polygon"), &Polygon2D::get_polygon);
328 
329 	ObjectTypeDB::bind_method(_MD("set_uv", "uv"), &Polygon2D::set_uv);
330 	ObjectTypeDB::bind_method(_MD("get_uv"), &Polygon2D::get_uv);
331 
332 	ObjectTypeDB::bind_method(_MD("set_color", "color"), &Polygon2D::set_color);
333 	ObjectTypeDB::bind_method(_MD("get_color"), &Polygon2D::get_color);
334 
335 	ObjectTypeDB::bind_method(_MD("set_vertex_colors", "vertex_colors"), &Polygon2D::set_vertex_colors);
336 	ObjectTypeDB::bind_method(_MD("get_vertex_colors"), &Polygon2D::get_vertex_colors);
337 
338 	ObjectTypeDB::bind_method(_MD("set_texture", "texture"), &Polygon2D::set_texture);
339 	ObjectTypeDB::bind_method(_MD("get_texture"), &Polygon2D::get_texture);
340 
341 	ObjectTypeDB::bind_method(_MD("set_texture_offset", "texture_offset"), &Polygon2D::set_texture_offset);
342 	ObjectTypeDB::bind_method(_MD("get_texture_offset"), &Polygon2D::get_texture_offset);
343 
344 	ObjectTypeDB::bind_method(_MD("set_texture_rotation", "texture_rotation"), &Polygon2D::set_texture_rotation);
345 	ObjectTypeDB::bind_method(_MD("get_texture_rotation"), &Polygon2D::get_texture_rotation);
346 
347 	ObjectTypeDB::bind_method(_MD("_set_texture_rotationd", "texture_rotation"), &Polygon2D::_set_texture_rotationd);
348 	ObjectTypeDB::bind_method(_MD("_get_texture_rotationd"), &Polygon2D::_get_texture_rotationd);
349 
350 	ObjectTypeDB::bind_method(_MD("set_texture_scale", "texture_scale"), &Polygon2D::set_texture_scale);
351 	ObjectTypeDB::bind_method(_MD("get_texture_scale"), &Polygon2D::get_texture_scale);
352 
353 	ObjectTypeDB::bind_method(_MD("set_invert", "invert"), &Polygon2D::set_invert);
354 	ObjectTypeDB::bind_method(_MD("get_invert"), &Polygon2D::get_invert);
355 
356 	ObjectTypeDB::bind_method(_MD("set_invert_border", "invert_border"), &Polygon2D::set_invert_border);
357 	ObjectTypeDB::bind_method(_MD("get_invert_border"), &Polygon2D::get_invert_border);
358 
359 	ObjectTypeDB::bind_method(_MD("set_offset", "offset"), &Polygon2D::set_offset);
360 	ObjectTypeDB::bind_method(_MD("get_offset"), &Polygon2D::get_offset);
361 
362 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY, "polygon"), _SCS("set_polygon"), _SCS("get_polygon"));
363 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY, "uv"), _SCS("set_uv"), _SCS("get_uv"));
364 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), _SCS("set_color"), _SCS("get_color"));
365 	ADD_PROPERTY(PropertyInfo(Variant::COLOR_ARRAY, "vertex_colors"), _SCS("set_vertex_colors"), _SCS("get_vertex_colors"));
366 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), _SCS("set_offset"), _SCS("get_offset"));
367 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture/texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"), _SCS("get_texture"));
368 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture/offset"), _SCS("set_texture_offset"), _SCS("get_texture_offset"));
369 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture/scale"), _SCS("set_texture_scale"), _SCS("get_texture_scale"));
370 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture/rotation", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), _SCS("_set_texture_rotationd"), _SCS("_get_texture_rotationd"));
371 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert/enable"), _SCS("set_invert"), _SCS("get_invert"));
372 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "invert/border", PROPERTY_HINT_RANGE, "0.1,16384,0.1"), _SCS("set_invert_border"), _SCS("get_invert_border"));
373 }
374 
Polygon2D()375 Polygon2D::Polygon2D() {
376 
377 	invert = 0;
378 	invert_border = 100;
379 	tex_rot = 0;
380 	tex_tile = true;
381 	tex_scale = Vector2(1, 1);
382 	color = Color(1, 1, 1);
383 	rect_cache_dirty = true;
384 }
385