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