1 | /**************************************************************************/ |
2 | /* polygon_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 "polygon_2d.h" |
32 | |
33 | #include "core/math/geometry_2d.h" |
34 | #include "skeleton_2d.h" |
35 | |
36 | #ifdef TOOLS_ENABLED |
37 | Dictionary Polygon2D::_edit_get_state() const { |
38 | Dictionary state = Node2D::_edit_get_state(); |
39 | state["offset" ] = offset; |
40 | return state; |
41 | } |
42 | |
43 | void Polygon2D::_edit_set_state(const Dictionary &p_state) { |
44 | Node2D::_edit_set_state(p_state); |
45 | set_offset(p_state["offset" ]); |
46 | } |
47 | |
48 | void Polygon2D::_edit_set_pivot(const Point2 &p_pivot) { |
49 | set_position(get_transform().xform(p_pivot)); |
50 | set_offset(get_offset() - p_pivot); |
51 | } |
52 | |
53 | Point2 Polygon2D::_edit_get_pivot() const { |
54 | return Vector2(); |
55 | } |
56 | |
57 | bool Polygon2D::_edit_use_pivot() const { |
58 | return true; |
59 | } |
60 | |
61 | Rect2 Polygon2D::_edit_get_rect() const { |
62 | if (rect_cache_dirty) { |
63 | int l = polygon.size(); |
64 | const Vector2 *r = polygon.ptr(); |
65 | item_rect = Rect2(); |
66 | for (int i = 0; i < l; i++) { |
67 | Vector2 pos = r[i] + offset; |
68 | if (i == 0) { |
69 | item_rect.position = pos; |
70 | } else { |
71 | item_rect.expand_to(pos); |
72 | } |
73 | } |
74 | rect_cache_dirty = false; |
75 | } |
76 | |
77 | return item_rect; |
78 | } |
79 | |
80 | bool Polygon2D::_edit_use_rect() const { |
81 | return polygon.size() > 0; |
82 | } |
83 | |
84 | bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { |
85 | Vector<Vector2> polygon2d = Variant(polygon); |
86 | if (internal_vertices > 0) { |
87 | polygon2d.resize(polygon2d.size() - internal_vertices); |
88 | } |
89 | return Geometry2D::is_point_in_polygon(p_point - get_offset(), polygon2d); |
90 | } |
91 | #endif |
92 | |
93 | void Polygon2D::_validate_property(PropertyInfo &p_property) const { |
94 | if (!invert && p_property.name == "invert_border" ) { |
95 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
96 | } |
97 | } |
98 | |
99 | void Polygon2D::_skeleton_bone_setup_changed() { |
100 | queue_redraw(); |
101 | } |
102 | |
103 | void Polygon2D::_notification(int p_what) { |
104 | switch (p_what) { |
105 | case NOTIFICATION_DRAW: { |
106 | if (polygon.size() < 3) { |
107 | return; |
108 | } |
109 | |
110 | Skeleton2D *skeleton_node = nullptr; |
111 | if (has_node(skeleton)) { |
112 | skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton)); |
113 | } |
114 | |
115 | ObjectID new_skeleton_id; |
116 | |
117 | if (skeleton_node && !invert && bone_weights.size()) { |
118 | RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); |
119 | new_skeleton_id = skeleton_node->get_instance_id(); |
120 | } else { |
121 | RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); |
122 | } |
123 | |
124 | if (new_skeleton_id != current_skeleton_id) { |
125 | Object *old_skeleton = ObjectDB::get_instance(current_skeleton_id); |
126 | if (old_skeleton) { |
127 | old_skeleton->disconnect("bone_setup_changed" , callable_mp(this, &Polygon2D::_skeleton_bone_setup_changed)); |
128 | } |
129 | |
130 | if (skeleton_node) { |
131 | skeleton_node->connect("bone_setup_changed" , callable_mp(this, &Polygon2D::_skeleton_bone_setup_changed)); |
132 | } |
133 | |
134 | current_skeleton_id = new_skeleton_id; |
135 | } |
136 | |
137 | Vector<Vector2> points; |
138 | Vector<Vector2> uvs; |
139 | Vector<int> bones; |
140 | Vector<float> weights; |
141 | |
142 | int len = polygon.size(); |
143 | if ((invert || polygons.size() == 0) && internal_vertices > 0) { |
144 | //if no polygons are around, internal vertices must not be drawn, else let them be |
145 | len -= internal_vertices; |
146 | } |
147 | |
148 | if (len <= 0) { |
149 | return; |
150 | } |
151 | points.resize(len); |
152 | |
153 | { |
154 | const Vector2 *polyr = polygon.ptr(); |
155 | for (int i = 0; i < len; i++) { |
156 | points.write[i] = polyr[i] + offset; |
157 | } |
158 | } |
159 | |
160 | if (invert) { |
161 | Rect2 bounds; |
162 | int highest_idx = -1; |
163 | real_t highest_y = -1e20; |
164 | real_t sum = 0.0; |
165 | |
166 | for (int i = 0; i < len; i++) { |
167 | if (i == 0) { |
168 | bounds.position = points[i]; |
169 | } else { |
170 | bounds.expand_to(points[i]); |
171 | } |
172 | if (points[i].y > highest_y) { |
173 | highest_idx = i; |
174 | highest_y = points[i].y; |
175 | } |
176 | int ni = (i + 1) % len; |
177 | sum += (points[ni].x - points[i].x) * (points[ni].y + points[i].y); |
178 | } |
179 | |
180 | bounds = bounds.grow(invert_border); |
181 | |
182 | Vector2 ep[7] = { |
183 | Vector2(points[highest_idx].x, points[highest_idx].y + invert_border), |
184 | Vector2(bounds.position + bounds.size), |
185 | Vector2(bounds.position + Vector2(bounds.size.x, 0)), |
186 | Vector2(bounds.position), |
187 | Vector2(bounds.position + Vector2(0, bounds.size.y)), |
188 | Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y + invert_border), |
189 | Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y), |
190 | }; |
191 | |
192 | if (sum > 0) { |
193 | SWAP(ep[1], ep[4]); |
194 | SWAP(ep[2], ep[3]); |
195 | SWAP(ep[5], ep[0]); |
196 | SWAP(ep[6], points.write[highest_idx]); |
197 | } |
198 | |
199 | points.resize(points.size() + 7); |
200 | for (int i = points.size() - 1; i >= highest_idx + 7; i--) { |
201 | points.write[i] = points[i - 7]; |
202 | } |
203 | |
204 | for (int i = 0; i < 7; i++) { |
205 | points.write[highest_idx + i + 1] = ep[i]; |
206 | } |
207 | |
208 | len = points.size(); |
209 | } |
210 | |
211 | if (texture.is_valid()) { |
212 | Transform2D texmat(tex_rot, tex_ofs); |
213 | texmat.scale(tex_scale); |
214 | Size2 tex_size = texture->get_size(); |
215 | |
216 | uvs.resize(len); |
217 | |
218 | if (points.size() == uv.size()) { |
219 | const Vector2 *uvr = uv.ptr(); |
220 | |
221 | for (int i = 0; i < len; i++) { |
222 | uvs.write[i] = texmat.xform(uvr[i]) / tex_size; |
223 | } |
224 | |
225 | } else { |
226 | for (int i = 0; i < len; i++) { |
227 | uvs.write[i] = texmat.xform(points[i]) / tex_size; |
228 | } |
229 | } |
230 | } |
231 | |
232 | if (skeleton_node && !invert && bone_weights.size()) { |
233 | //a skeleton is set! fill indices and weights |
234 | int vc = len; |
235 | bones.resize(vc * 4); |
236 | weights.resize(vc * 4); |
237 | |
238 | int *bonesw = bones.ptrw(); |
239 | float *weightsw = weights.ptrw(); |
240 | |
241 | for (int i = 0; i < vc * 4; i++) { |
242 | bonesw[i] = 0; |
243 | weightsw[i] = 0; |
244 | } |
245 | |
246 | for (int i = 0; i < bone_weights.size(); i++) { |
247 | if (bone_weights[i].weights.size() != points.size()) { |
248 | continue; //different number of vertices, sorry not using. |
249 | } |
250 | if (!skeleton_node->has_node(bone_weights[i].path)) { |
251 | continue; //node does not exist |
252 | } |
253 | Bone2D *bone = Object::cast_to<Bone2D>(skeleton_node->get_node(bone_weights[i].path)); |
254 | if (!bone) { |
255 | continue; |
256 | } |
257 | |
258 | int bone_index = bone->get_index_in_skeleton(); |
259 | const float *r = bone_weights[i].weights.ptr(); |
260 | for (int j = 0; j < vc; j++) { |
261 | if (r[j] == 0.0) { |
262 | continue; //weight is unpainted, skip |
263 | } |
264 | //find an index with a weight |
265 | for (int k = 0; k < 4; k++) { |
266 | if (weightsw[j * 4 + k] < r[j]) { |
267 | //this is less than this weight, insert weight! |
268 | for (int l = 3; l > k; l--) { |
269 | weightsw[j * 4 + l] = weightsw[j * 4 + l - 1]; |
270 | bonesw[j * 4 + l] = bonesw[j * 4 + l - 1]; |
271 | } |
272 | weightsw[j * 4 + k] = r[j]; |
273 | bonesw[j * 4 + k] = bone_index; |
274 | break; |
275 | } |
276 | } |
277 | } |
278 | } |
279 | |
280 | //normalize the weights |
281 | for (int i = 0; i < vc; i++) { |
282 | real_t tw = 0.0; |
283 | for (int j = 0; j < 4; j++) { |
284 | tw += weightsw[i * 4 + j]; |
285 | } |
286 | if (tw == 0) { |
287 | continue; //unpainted, do nothing |
288 | } |
289 | |
290 | //normalize |
291 | for (int j = 0; j < 4; j++) { |
292 | weightsw[i * 4 + j] /= tw; |
293 | } |
294 | } |
295 | } |
296 | |
297 | Vector<Color> colors; |
298 | colors.resize(len); |
299 | |
300 | if (vertex_colors.size() == points.size()) { |
301 | const Color *color_r = vertex_colors.ptr(); |
302 | for (int i = 0; i < len; i++) { |
303 | colors.write[i] = color_r[i]; |
304 | } |
305 | } else { |
306 | for (int i = 0; i < len; i++) { |
307 | colors.write[i] = color; |
308 | } |
309 | } |
310 | |
311 | Vector<int> index_array; |
312 | |
313 | if (invert || polygons.size() == 0) { |
314 | index_array = Geometry2D::triangulate_polygon(points); |
315 | } else { |
316 | //draw individual polygons |
317 | for (int i = 0; i < polygons.size(); i++) { |
318 | Vector<int> src_indices = polygons[i]; |
319 | int ic = src_indices.size(); |
320 | if (ic < 3) { |
321 | continue; |
322 | } |
323 | const int *r = src_indices.ptr(); |
324 | |
325 | Vector<Vector2> tmp_points; |
326 | tmp_points.resize(ic); |
327 | |
328 | for (int j = 0; j < ic; j++) { |
329 | int idx = r[j]; |
330 | ERR_CONTINUE(idx < 0 || idx >= points.size()); |
331 | tmp_points.write[j] = points[r[j]]; |
332 | } |
333 | Vector<int> indices = Geometry2D::triangulate_polygon(tmp_points); |
334 | int ic2 = indices.size(); |
335 | const int *r2 = indices.ptr(); |
336 | |
337 | int bic = index_array.size(); |
338 | index_array.resize(bic + ic2); |
339 | int *w2 = index_array.ptrw(); |
340 | |
341 | for (int j = 0; j < ic2; j++) { |
342 | w2[j + bic] = r[r2[j]]; |
343 | } |
344 | } |
345 | } |
346 | |
347 | RS::get_singleton()->mesh_clear(mesh); |
348 | |
349 | if (index_array.size()) { |
350 | Array arr; |
351 | arr.resize(RS::ARRAY_MAX); |
352 | arr[RS::ARRAY_VERTEX] = points; |
353 | if (uvs.size() == points.size()) { |
354 | arr[RS::ARRAY_TEX_UV] = uvs; |
355 | } |
356 | if (colors.size() == points.size()) { |
357 | arr[RS::ARRAY_COLOR] = colors; |
358 | } |
359 | |
360 | if (bones.size() == points.size() * 4) { |
361 | arr[RS::ARRAY_BONES] = bones; |
362 | arr[RS::ARRAY_WEIGHTS] = weights; |
363 | } |
364 | |
365 | arr[RS::ARRAY_INDEX] = index_array; |
366 | |
367 | RS::get_singleton()->mesh_add_surface_from_arrays(mesh, RS::PRIMITIVE_TRIANGLES, arr, Array(), Dictionary(), RS::ARRAY_FLAG_USE_2D_VERTICES); |
368 | RS::get_singleton()->canvas_item_add_mesh(get_canvas_item(), mesh, Transform2D(), Color(1, 1, 1), texture.is_valid() ? texture->get_rid() : RID()); |
369 | } |
370 | |
371 | } break; |
372 | } |
373 | } |
374 | |
375 | void Polygon2D::set_polygon(const Vector<Vector2> &p_polygon) { |
376 | polygon = p_polygon; |
377 | rect_cache_dirty = true; |
378 | queue_redraw(); |
379 | } |
380 | |
381 | Vector<Vector2> Polygon2D::get_polygon() const { |
382 | return polygon; |
383 | } |
384 | |
385 | void Polygon2D::set_internal_vertex_count(int p_count) { |
386 | internal_vertices = p_count; |
387 | } |
388 | |
389 | int Polygon2D::get_internal_vertex_count() const { |
390 | return internal_vertices; |
391 | } |
392 | |
393 | void Polygon2D::set_uv(const Vector<Vector2> &p_uv) { |
394 | uv = p_uv; |
395 | queue_redraw(); |
396 | } |
397 | |
398 | Vector<Vector2> Polygon2D::get_uv() const { |
399 | return uv; |
400 | } |
401 | |
402 | void Polygon2D::set_polygons(const Array &p_polygons) { |
403 | polygons = p_polygons; |
404 | queue_redraw(); |
405 | } |
406 | |
407 | Array Polygon2D::get_polygons() const { |
408 | return polygons; |
409 | } |
410 | |
411 | void Polygon2D::set_color(const Color &p_color) { |
412 | color = p_color; |
413 | queue_redraw(); |
414 | } |
415 | |
416 | Color Polygon2D::get_color() const { |
417 | return color; |
418 | } |
419 | |
420 | void Polygon2D::set_vertex_colors(const Vector<Color> &p_colors) { |
421 | vertex_colors = p_colors; |
422 | queue_redraw(); |
423 | } |
424 | |
425 | Vector<Color> Polygon2D::get_vertex_colors() const { |
426 | return vertex_colors; |
427 | } |
428 | |
429 | void Polygon2D::set_texture(const Ref<Texture2D> &p_texture) { |
430 | texture = p_texture; |
431 | queue_redraw(); |
432 | } |
433 | |
434 | Ref<Texture2D> Polygon2D::get_texture() const { |
435 | return texture; |
436 | } |
437 | |
438 | void Polygon2D::set_texture_offset(const Vector2 &p_offset) { |
439 | tex_ofs = p_offset; |
440 | queue_redraw(); |
441 | } |
442 | |
443 | Vector2 Polygon2D::get_texture_offset() const { |
444 | return tex_ofs; |
445 | } |
446 | |
447 | void Polygon2D::set_texture_rotation(real_t p_rot) { |
448 | tex_rot = p_rot; |
449 | queue_redraw(); |
450 | } |
451 | |
452 | real_t Polygon2D::get_texture_rotation() const { |
453 | return tex_rot; |
454 | } |
455 | |
456 | void Polygon2D::set_texture_scale(const Size2 &p_scale) { |
457 | tex_scale = p_scale; |
458 | queue_redraw(); |
459 | } |
460 | |
461 | Size2 Polygon2D::get_texture_scale() const { |
462 | return tex_scale; |
463 | } |
464 | |
465 | void Polygon2D::set_invert(bool p_invert) { |
466 | invert = p_invert; |
467 | queue_redraw(); |
468 | notify_property_list_changed(); |
469 | } |
470 | |
471 | bool Polygon2D::get_invert() const { |
472 | return invert; |
473 | } |
474 | |
475 | void Polygon2D::set_antialiased(bool p_antialiased) { |
476 | antialiased = p_antialiased; |
477 | queue_redraw(); |
478 | } |
479 | |
480 | bool Polygon2D::get_antialiased() const { |
481 | return antialiased; |
482 | } |
483 | |
484 | void Polygon2D::set_invert_border(real_t p_invert_border) { |
485 | invert_border = p_invert_border; |
486 | queue_redraw(); |
487 | } |
488 | |
489 | real_t Polygon2D::get_invert_border() const { |
490 | return invert_border; |
491 | } |
492 | |
493 | void Polygon2D::set_offset(const Vector2 &p_offset) { |
494 | offset = p_offset; |
495 | rect_cache_dirty = true; |
496 | queue_redraw(); |
497 | } |
498 | |
499 | Vector2 Polygon2D::get_offset() const { |
500 | return offset; |
501 | } |
502 | |
503 | void Polygon2D::add_bone(const NodePath &p_path, const Vector<float> &p_weights) { |
504 | Bone bone; |
505 | bone.path = p_path; |
506 | bone.weights = p_weights; |
507 | bone_weights.push_back(bone); |
508 | } |
509 | |
510 | int Polygon2D::get_bone_count() const { |
511 | return bone_weights.size(); |
512 | } |
513 | |
514 | NodePath Polygon2D::get_bone_path(int p_index) const { |
515 | ERR_FAIL_INDEX_V(p_index, bone_weights.size(), NodePath()); |
516 | return bone_weights[p_index].path; |
517 | } |
518 | |
519 | Vector<float> Polygon2D::get_bone_weights(int p_index) const { |
520 | ERR_FAIL_INDEX_V(p_index, bone_weights.size(), Vector<float>()); |
521 | return bone_weights[p_index].weights; |
522 | } |
523 | |
524 | void Polygon2D::erase_bone(int p_idx) { |
525 | ERR_FAIL_INDEX(p_idx, bone_weights.size()); |
526 | bone_weights.remove_at(p_idx); |
527 | } |
528 | |
529 | void Polygon2D::clear_bones() { |
530 | bone_weights.clear(); |
531 | } |
532 | |
533 | void Polygon2D::set_bone_weights(int p_index, const Vector<float> &p_weights) { |
534 | ERR_FAIL_INDEX(p_index, bone_weights.size()); |
535 | bone_weights.write[p_index].weights = p_weights; |
536 | queue_redraw(); |
537 | } |
538 | |
539 | void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) { |
540 | ERR_FAIL_INDEX(p_index, bone_weights.size()); |
541 | bone_weights.write[p_index].path = p_path; |
542 | queue_redraw(); |
543 | } |
544 | |
545 | Array Polygon2D::_get_bones() const { |
546 | Array bones; |
547 | for (int i = 0; i < get_bone_count(); i++) { |
548 | // Convert path property to String to avoid errors due to invalid node path in editor, |
549 | // because it's relative to the Skeleton2D node and not Polygon2D. |
550 | bones.push_back(String(get_bone_path(i))); |
551 | bones.push_back(get_bone_weights(i)); |
552 | } |
553 | return bones; |
554 | } |
555 | |
556 | void Polygon2D::_set_bones(const Array &p_bones) { |
557 | ERR_FAIL_COND(p_bones.size() & 1); |
558 | clear_bones(); |
559 | for (int i = 0; i < p_bones.size(); i += 2) { |
560 | // Convert back from String to NodePath. |
561 | add_bone(NodePath(p_bones[i]), p_bones[i + 1]); |
562 | } |
563 | } |
564 | |
565 | void Polygon2D::set_skeleton(const NodePath &p_skeleton) { |
566 | if (skeleton == p_skeleton) { |
567 | return; |
568 | } |
569 | skeleton = p_skeleton; |
570 | queue_redraw(); |
571 | } |
572 | |
573 | NodePath Polygon2D::get_skeleton() const { |
574 | return skeleton; |
575 | } |
576 | |
577 | void Polygon2D::_bind_methods() { |
578 | ClassDB::bind_method(D_METHOD("set_polygon" , "polygon" ), &Polygon2D::set_polygon); |
579 | ClassDB::bind_method(D_METHOD("get_polygon" ), &Polygon2D::get_polygon); |
580 | |
581 | ClassDB::bind_method(D_METHOD("set_uv" , "uv" ), &Polygon2D::set_uv); |
582 | ClassDB::bind_method(D_METHOD("get_uv" ), &Polygon2D::get_uv); |
583 | |
584 | ClassDB::bind_method(D_METHOD("set_color" , "color" ), &Polygon2D::set_color); |
585 | ClassDB::bind_method(D_METHOD("get_color" ), &Polygon2D::get_color); |
586 | |
587 | ClassDB::bind_method(D_METHOD("set_polygons" , "polygons" ), &Polygon2D::set_polygons); |
588 | ClassDB::bind_method(D_METHOD("get_polygons" ), &Polygon2D::get_polygons); |
589 | |
590 | ClassDB::bind_method(D_METHOD("set_vertex_colors" , "vertex_colors" ), &Polygon2D::set_vertex_colors); |
591 | ClassDB::bind_method(D_METHOD("get_vertex_colors" ), &Polygon2D::get_vertex_colors); |
592 | |
593 | ClassDB::bind_method(D_METHOD("set_texture" , "texture" ), &Polygon2D::set_texture); |
594 | ClassDB::bind_method(D_METHOD("get_texture" ), &Polygon2D::get_texture); |
595 | |
596 | ClassDB::bind_method(D_METHOD("set_texture_offset" , "texture_offset" ), &Polygon2D::set_texture_offset); |
597 | ClassDB::bind_method(D_METHOD("get_texture_offset" ), &Polygon2D::get_texture_offset); |
598 | |
599 | ClassDB::bind_method(D_METHOD("set_texture_rotation" , "texture_rotation" ), &Polygon2D::set_texture_rotation); |
600 | ClassDB::bind_method(D_METHOD("get_texture_rotation" ), &Polygon2D::get_texture_rotation); |
601 | |
602 | ClassDB::bind_method(D_METHOD("set_texture_scale" , "texture_scale" ), &Polygon2D::set_texture_scale); |
603 | ClassDB::bind_method(D_METHOD("get_texture_scale" ), &Polygon2D::get_texture_scale); |
604 | |
605 | ClassDB::bind_method(D_METHOD("set_invert_enabled" , "invert" ), &Polygon2D::set_invert); |
606 | ClassDB::bind_method(D_METHOD("get_invert_enabled" ), &Polygon2D::get_invert); |
607 | |
608 | ClassDB::bind_method(D_METHOD("set_antialiased" , "antialiased" ), &Polygon2D::set_antialiased); |
609 | ClassDB::bind_method(D_METHOD("get_antialiased" ), &Polygon2D::get_antialiased); |
610 | |
611 | ClassDB::bind_method(D_METHOD("set_invert_border" , "invert_border" ), &Polygon2D::set_invert_border); |
612 | ClassDB::bind_method(D_METHOD("get_invert_border" ), &Polygon2D::get_invert_border); |
613 | |
614 | ClassDB::bind_method(D_METHOD("set_offset" , "offset" ), &Polygon2D::set_offset); |
615 | ClassDB::bind_method(D_METHOD("get_offset" ), &Polygon2D::get_offset); |
616 | |
617 | ClassDB::bind_method(D_METHOD("add_bone" , "path" , "weights" ), &Polygon2D::add_bone); |
618 | ClassDB::bind_method(D_METHOD("get_bone_count" ), &Polygon2D::get_bone_count); |
619 | ClassDB::bind_method(D_METHOD("get_bone_path" , "index" ), &Polygon2D::get_bone_path); |
620 | ClassDB::bind_method(D_METHOD("get_bone_weights" , "index" ), &Polygon2D::get_bone_weights); |
621 | ClassDB::bind_method(D_METHOD("erase_bone" , "index" ), &Polygon2D::erase_bone); |
622 | ClassDB::bind_method(D_METHOD("clear_bones" ), &Polygon2D::clear_bones); |
623 | ClassDB::bind_method(D_METHOD("set_bone_path" , "index" , "path" ), &Polygon2D::set_bone_path); |
624 | ClassDB::bind_method(D_METHOD("set_bone_weights" , "index" , "weights" ), &Polygon2D::set_bone_weights); |
625 | |
626 | ClassDB::bind_method(D_METHOD("set_skeleton" , "skeleton" ), &Polygon2D::set_skeleton); |
627 | ClassDB::bind_method(D_METHOD("get_skeleton" ), &Polygon2D::get_skeleton); |
628 | |
629 | ClassDB::bind_method(D_METHOD("set_internal_vertex_count" , "internal_vertex_count" ), &Polygon2D::set_internal_vertex_count); |
630 | ClassDB::bind_method(D_METHOD("get_internal_vertex_count" ), &Polygon2D::get_internal_vertex_count); |
631 | |
632 | ClassDB::bind_method(D_METHOD("_set_bones" , "bones" ), &Polygon2D::_set_bones); |
633 | ClassDB::bind_method(D_METHOD("_get_bones" ), &Polygon2D::_get_bones); |
634 | |
635 | ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color" ), "set_color" , "get_color" ); |
636 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset" ), "set_offset" , "get_offset" ); |
637 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "antialiased" ), "set_antialiased" , "get_antialiased" ); |
638 | |
639 | ADD_GROUP("Texture" , "texture_" ); |
640 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture" , PROPERTY_HINT_RESOURCE_TYPE, "Texture2D" ), "set_texture" , "get_texture" ); |
641 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset" , PROPERTY_HINT_NONE, "suffix:px" ), "set_texture_offset" , "get_texture_offset" ); |
642 | ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale" , PROPERTY_HINT_LINK), "set_texture_scale" , "get_texture_scale" ); |
643 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "texture_rotation" , PROPERTY_HINT_RANGE, "-360,360,0.1,or_less,or_greater,radians" ), "set_texture_rotation" , "get_texture_rotation" ); |
644 | |
645 | ADD_GROUP("Skeleton" , "" ); |
646 | ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton" , PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton2D" ), "set_skeleton" , "get_skeleton" ); |
647 | |
648 | ADD_GROUP("Invert" , "invert_" ); |
649 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enabled" ), "set_invert_enabled" , "get_invert_enabled" ); |
650 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "invert_border" , PROPERTY_HINT_RANGE, "0.1,16384,0.1,suffix:px" ), "set_invert_border" , "get_invert_border" ); |
651 | |
652 | ADD_GROUP("Data" , "" ); |
653 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "polygon" ), "set_polygon" , "get_polygon" ); |
654 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "uv" ), "set_uv" , "get_uv" ); |
655 | ADD_PROPERTY(PropertyInfo(Variant::PACKED_COLOR_ARRAY, "vertex_colors" ), "set_vertex_colors" , "get_vertex_colors" ); |
656 | ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons" ), "set_polygons" , "get_polygons" ); |
657 | ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bones" , PROPERTY_HINT_NONE, "" , PROPERTY_USAGE_NO_EDITOR), "_set_bones" , "_get_bones" ); |
658 | ADD_PROPERTY(PropertyInfo(Variant::INT, "internal_vertex_count" , PROPERTY_HINT_RANGE, "0,1000" ), "set_internal_vertex_count" , "get_internal_vertex_count" ); |
659 | } |
660 | |
661 | Polygon2D::Polygon2D() { |
662 | mesh = RS::get_singleton()->mesh_create(); |
663 | } |
664 | |
665 | Polygon2D::~Polygon2D() { |
666 | // This will free the internally-allocated mesh instance, if allocated. |
667 | ERR_FAIL_NULL(RenderingServer::get_singleton()); |
668 | RS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); |
669 | RS::get_singleton()->free(mesh); |
670 | } |
671 | |