1 /*************************************************************************/
2 /*  sprite_3d.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 "sprite_3d.h"
32 #include "core/core_string_names.h"
33 #include "scene/scene_string_names.h"
34 
_get_color_accum()35 Color SpriteBase3D::_get_color_accum() {
36 
37 	if (!color_dirty)
38 		return color_accum;
39 
40 	if (parent_sprite)
41 		color_accum = parent_sprite->_get_color_accum();
42 	else
43 		color_accum = Color(1, 1, 1, 1);
44 
45 	color_accum.r *= modulate.r;
46 	color_accum.g *= modulate.g;
47 	color_accum.b *= modulate.b;
48 	color_accum.a *= modulate.a;
49 	color_dirty = false;
50 	return color_accum;
51 }
52 
_propagate_color_changed()53 void SpriteBase3D::_propagate_color_changed() {
54 
55 	if (color_dirty)
56 		return;
57 
58 	color_dirty = true;
59 	_queue_update();
60 
61 	for (List<SpriteBase3D *>::Element *E = children.front(); E; E = E->next()) {
62 
63 		E->get()->_propagate_color_changed();
64 	}
65 }
66 
_notification(int p_what)67 void SpriteBase3D::_notification(int p_what) {
68 
69 	if (p_what == NOTIFICATION_ENTER_TREE) {
70 
71 		if (!pending_update)
72 			_im_update();
73 
74 		parent_sprite = Object::cast_to<SpriteBase3D>(get_parent());
75 		if (parent_sprite) {
76 			pI = parent_sprite->children.push_back(this);
77 		}
78 	}
79 
80 	if (p_what == NOTIFICATION_EXIT_TREE) {
81 
82 		if (parent_sprite) {
83 
84 			parent_sprite->children.erase(pI);
85 			pI = NULL;
86 			parent_sprite = NULL;
87 		}
88 	}
89 }
90 
set_centered(bool p_center)91 void SpriteBase3D::set_centered(bool p_center) {
92 
93 	centered = p_center;
94 	_queue_update();
95 }
96 
is_centered() const97 bool SpriteBase3D::is_centered() const {
98 
99 	return centered;
100 }
101 
set_offset(const Point2 & p_offset)102 void SpriteBase3D::set_offset(const Point2 &p_offset) {
103 
104 	offset = p_offset;
105 	_queue_update();
106 }
get_offset() const107 Point2 SpriteBase3D::get_offset() const {
108 
109 	return offset;
110 }
111 
set_flip_h(bool p_flip)112 void SpriteBase3D::set_flip_h(bool p_flip) {
113 
114 	hflip = p_flip;
115 	_queue_update();
116 }
is_flipped_h() const117 bool SpriteBase3D::is_flipped_h() const {
118 
119 	return hflip;
120 }
121 
set_flip_v(bool p_flip)122 void SpriteBase3D::set_flip_v(bool p_flip) {
123 
124 	vflip = p_flip;
125 	_queue_update();
126 }
is_flipped_v() const127 bool SpriteBase3D::is_flipped_v() const {
128 
129 	return vflip;
130 }
131 
set_modulate(const Color & p_color)132 void SpriteBase3D::set_modulate(const Color &p_color) {
133 
134 	modulate = p_color;
135 	_propagate_color_changed();
136 	_queue_update();
137 }
138 
get_modulate() const139 Color SpriteBase3D::get_modulate() const {
140 
141 	return modulate;
142 }
143 
set_pixel_size(float p_amount)144 void SpriteBase3D::set_pixel_size(float p_amount) {
145 
146 	pixel_size = p_amount;
147 	_queue_update();
148 }
get_pixel_size() const149 float SpriteBase3D::get_pixel_size() const {
150 
151 	return pixel_size;
152 }
153 
set_opacity(float p_amount)154 void SpriteBase3D::set_opacity(float p_amount) {
155 
156 	opacity = p_amount;
157 	_queue_update();
158 }
get_opacity() const159 float SpriteBase3D::get_opacity() const {
160 
161 	return opacity;
162 }
163 
set_axis(Vector3::Axis p_axis)164 void SpriteBase3D::set_axis(Vector3::Axis p_axis) {
165 
166 	ERR_FAIL_INDEX(p_axis, 3);
167 	axis = p_axis;
168 	_queue_update();
169 }
get_axis() const170 Vector3::Axis SpriteBase3D::get_axis() const {
171 
172 	return axis;
173 }
174 
_im_update()175 void SpriteBase3D::_im_update() {
176 
177 	_draw();
178 
179 	pending_update = false;
180 
181 	//texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
182 }
183 
_queue_update()184 void SpriteBase3D::_queue_update() {
185 
186 	if (pending_update)
187 		return;
188 
189 	triangle_mesh.unref();
190 	update_gizmo();
191 
192 	pending_update = true;
193 	call_deferred(SceneStringNames::get_singleton()->_im_update);
194 }
195 
get_aabb() const196 AABB SpriteBase3D::get_aabb() const {
197 
198 	return aabb;
199 }
get_faces(uint32_t p_usage_flags) const200 PoolVector<Face3> SpriteBase3D::get_faces(uint32_t p_usage_flags) const {
201 
202 	return PoolVector<Face3>();
203 }
204 
generate_triangle_mesh() const205 Ref<TriangleMesh> SpriteBase3D::generate_triangle_mesh() const {
206 	if (triangle_mesh.is_valid())
207 		return triangle_mesh;
208 
209 	PoolVector<Vector3> faces;
210 	faces.resize(6);
211 	PoolVector<Vector3>::Write facesw = faces.write();
212 
213 	Rect2 final_rect = get_item_rect();
214 
215 	if (final_rect.size.x == 0 || final_rect.size.y == 0)
216 		return Ref<TriangleMesh>();
217 
218 	float pixel_size = get_pixel_size();
219 
220 	Vector2 vertices[4] = {
221 
222 		(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
223 		(final_rect.position + final_rect.size) * pixel_size,
224 		(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
225 		final_rect.position * pixel_size,
226 
227 	};
228 
229 	int x_axis = ((axis + 1) % 3);
230 	int y_axis = ((axis + 2) % 3);
231 
232 	if (axis != Vector3::AXIS_Z) {
233 		SWAP(x_axis, y_axis);
234 
235 		for (int i = 0; i < 4; i++) {
236 			if (axis == Vector3::AXIS_Y) {
237 				vertices[i].y = -vertices[i].y;
238 			} else if (axis == Vector3::AXIS_X) {
239 				vertices[i].x = -vertices[i].x;
240 			}
241 		}
242 	}
243 
244 	static const int indices[6] = {
245 		0, 1, 2,
246 		0, 2, 3
247 	};
248 
249 	for (int j = 0; j < 6; j++) {
250 		int i = indices[j];
251 		Vector3 vtx;
252 		vtx[x_axis] = vertices[i][0];
253 		vtx[y_axis] = vertices[i][1];
254 		facesw[j] = vtx;
255 	}
256 
257 	facesw.release();
258 
259 	triangle_mesh = Ref<TriangleMesh>(memnew(TriangleMesh));
260 	triangle_mesh->create(faces);
261 
262 	return triangle_mesh;
263 }
264 
set_draw_flag(DrawFlags p_flag,bool p_enable)265 void SpriteBase3D::set_draw_flag(DrawFlags p_flag, bool p_enable) {
266 
267 	ERR_FAIL_INDEX(p_flag, FLAG_MAX);
268 	flags[p_flag] = p_enable;
269 	_queue_update();
270 }
271 
get_draw_flag(DrawFlags p_flag) const272 bool SpriteBase3D::get_draw_flag(DrawFlags p_flag) const {
273 	ERR_FAIL_INDEX_V(p_flag, FLAG_MAX, false);
274 	return flags[p_flag];
275 }
276 
set_alpha_cut_mode(AlphaCutMode p_mode)277 void SpriteBase3D::set_alpha_cut_mode(AlphaCutMode p_mode) {
278 
279 	ERR_FAIL_INDEX(p_mode, 3);
280 	alpha_cut = p_mode;
281 	_queue_update();
282 }
283 
get_alpha_cut_mode() const284 SpriteBase3D::AlphaCutMode SpriteBase3D::get_alpha_cut_mode() const {
285 
286 	return alpha_cut;
287 }
288 
set_billboard_mode(SpatialMaterial::BillboardMode p_mode)289 void SpriteBase3D::set_billboard_mode(SpatialMaterial::BillboardMode p_mode) {
290 
291 	ERR_FAIL_INDEX(p_mode, 3);
292 	billboard_mode = p_mode;
293 	_queue_update();
294 }
295 
get_billboard_mode() const296 SpatialMaterial::BillboardMode SpriteBase3D::get_billboard_mode() const {
297 
298 	return billboard_mode;
299 }
300 
_bind_methods()301 void SpriteBase3D::_bind_methods() {
302 
303 	ClassDB::bind_method(D_METHOD("set_centered", "centered"), &SpriteBase3D::set_centered);
304 	ClassDB::bind_method(D_METHOD("is_centered"), &SpriteBase3D::is_centered);
305 
306 	ClassDB::bind_method(D_METHOD("set_offset", "offset"), &SpriteBase3D::set_offset);
307 	ClassDB::bind_method(D_METHOD("get_offset"), &SpriteBase3D::get_offset);
308 
309 	ClassDB::bind_method(D_METHOD("set_flip_h", "flip_h"), &SpriteBase3D::set_flip_h);
310 	ClassDB::bind_method(D_METHOD("is_flipped_h"), &SpriteBase3D::is_flipped_h);
311 
312 	ClassDB::bind_method(D_METHOD("set_flip_v", "flip_v"), &SpriteBase3D::set_flip_v);
313 	ClassDB::bind_method(D_METHOD("is_flipped_v"), &SpriteBase3D::is_flipped_v);
314 
315 	ClassDB::bind_method(D_METHOD("set_modulate", "modulate"), &SpriteBase3D::set_modulate);
316 	ClassDB::bind_method(D_METHOD("get_modulate"), &SpriteBase3D::get_modulate);
317 
318 	ClassDB::bind_method(D_METHOD("set_opacity", "opacity"), &SpriteBase3D::set_opacity);
319 	ClassDB::bind_method(D_METHOD("get_opacity"), &SpriteBase3D::get_opacity);
320 
321 	ClassDB::bind_method(D_METHOD("set_pixel_size", "pixel_size"), &SpriteBase3D::set_pixel_size);
322 	ClassDB::bind_method(D_METHOD("get_pixel_size"), &SpriteBase3D::get_pixel_size);
323 
324 	ClassDB::bind_method(D_METHOD("set_axis", "axis"), &SpriteBase3D::set_axis);
325 	ClassDB::bind_method(D_METHOD("get_axis"), &SpriteBase3D::get_axis);
326 
327 	ClassDB::bind_method(D_METHOD("set_draw_flag", "flag", "enabled"), &SpriteBase3D::set_draw_flag);
328 	ClassDB::bind_method(D_METHOD("get_draw_flag", "flag"), &SpriteBase3D::get_draw_flag);
329 
330 	ClassDB::bind_method(D_METHOD("set_alpha_cut_mode", "mode"), &SpriteBase3D::set_alpha_cut_mode);
331 	ClassDB::bind_method(D_METHOD("get_alpha_cut_mode"), &SpriteBase3D::get_alpha_cut_mode);
332 
333 	ClassDB::bind_method(D_METHOD("set_billboard_mode", "mode"), &SpriteBase3D::set_billboard_mode);
334 	ClassDB::bind_method(D_METHOD("get_billboard_mode"), &SpriteBase3D::get_billboard_mode);
335 
336 	ClassDB::bind_method(D_METHOD("get_item_rect"), &SpriteBase3D::get_item_rect);
337 	ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &SpriteBase3D::generate_triangle_mesh);
338 
339 	ClassDB::bind_method(D_METHOD("_queue_update"), &SpriteBase3D::_queue_update);
340 	ClassDB::bind_method(D_METHOD("_im_update"), &SpriteBase3D::_im_update);
341 
342 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
343 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
344 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_h"), "set_flip_h", "is_flipped_h");
345 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_v"), "set_flip_v", "is_flipped_v");
346 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "modulate"), "set_modulate", "get_modulate");
347 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "opacity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_opacity", "get_opacity");
348 	ADD_PROPERTY(PropertyInfo(Variant::REAL, "pixel_size", PROPERTY_HINT_RANGE, "0.0001,128,0.0001"), "set_pixel_size", "get_pixel_size");
349 	ADD_PROPERTY(PropertyInfo(Variant::INT, "axis", PROPERTY_HINT_ENUM, "X-Axis,Y-Axis,Z-Axis"), "set_axis", "get_axis");
350 	ADD_GROUP("Flags", "");
351 	ADD_PROPERTY(PropertyInfo(Variant::INT, "billboard", PROPERTY_HINT_ENUM, "Disabled,Enabled,Y-Billboard"), "set_billboard_mode", "get_billboard_mode");
352 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "transparent"), "set_draw_flag", "get_draw_flag", FLAG_TRANSPARENT);
353 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "shaded"), "set_draw_flag", "get_draw_flag", FLAG_SHADED);
354 	ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "double_sided"), "set_draw_flag", "get_draw_flag", FLAG_DOUBLE_SIDED);
355 	ADD_PROPERTY(PropertyInfo(Variant::INT, "alpha_cut", PROPERTY_HINT_ENUM, "Disabled,Discard,Opaque Pre-Pass"), "set_alpha_cut_mode", "get_alpha_cut_mode");
356 
357 	BIND_ENUM_CONSTANT(FLAG_TRANSPARENT);
358 	BIND_ENUM_CONSTANT(FLAG_SHADED);
359 	BIND_ENUM_CONSTANT(FLAG_DOUBLE_SIDED);
360 	BIND_ENUM_CONSTANT(FLAG_MAX);
361 
362 	BIND_ENUM_CONSTANT(ALPHA_CUT_DISABLED);
363 	BIND_ENUM_CONSTANT(ALPHA_CUT_DISCARD);
364 	BIND_ENUM_CONSTANT(ALPHA_CUT_OPAQUE_PREPASS);
365 }
366 
SpriteBase3D()367 SpriteBase3D::SpriteBase3D() {
368 
369 	color_dirty = true;
370 	centered = true;
371 	hflip = false;
372 	vflip = false;
373 	parent_sprite = NULL;
374 	pI = NULL;
375 
376 	for (int i = 0; i < FLAG_MAX; i++)
377 		flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
378 
379 	alpha_cut = ALPHA_CUT_DISABLED;
380 	billboard_mode = SpatialMaterial::BILLBOARD_DISABLED;
381 	axis = Vector3::AXIS_Z;
382 	pixel_size = 0.01;
383 	modulate = Color(1, 1, 1, 1);
384 	pending_update = false;
385 	opacity = 1.0;
386 
387 	material = VisualServer::get_singleton()->material_create();
388 	// Set defaults for material, names need to match up those in SpatialMaterial
389 	VS::get_singleton()->material_set_param(material, "albedo", Color(1, 1, 1, 1));
390 	VS::get_singleton()->material_set_param(material, "specular", 0.5);
391 	VS::get_singleton()->material_set_param(material, "metallic", 0.0);
392 	VS::get_singleton()->material_set_param(material, "roughness", 1.0);
393 	VS::get_singleton()->material_set_param(material, "uv1_offset", Vector3(0, 0, 0));
394 	VS::get_singleton()->material_set_param(material, "uv1_scale", Vector3(1, 1, 1));
395 	VS::get_singleton()->material_set_param(material, "uv2_offset", Vector3(0, 0, 0));
396 	VS::get_singleton()->material_set_param(material, "uv2_scale", Vector3(1, 1, 1));
397 
398 	mesh = VisualServer::get_singleton()->mesh_create();
399 
400 	PoolVector3Array mesh_vertices;
401 	PoolVector3Array mesh_normals;
402 	PoolRealArray mesh_tangents;
403 	PoolColorArray mesh_colors;
404 	PoolVector2Array mesh_uvs;
405 
406 	mesh_vertices.resize(4);
407 	mesh_normals.resize(4);
408 	mesh_tangents.resize(16);
409 	mesh_colors.resize(4);
410 	mesh_uvs.resize(4);
411 
412 	// create basic mesh and store format information
413 	for (int i = 0; i < 4; i++) {
414 		mesh_normals.write()[i] = Vector3(0.0, 0.0, 0.0);
415 		mesh_tangents.write()[i * 4 + 0] = 0.0;
416 		mesh_tangents.write()[i * 4 + 1] = 0.0;
417 		mesh_tangents.write()[i * 4 + 2] = 0.0;
418 		mesh_tangents.write()[i * 4 + 3] = 0.0;
419 		mesh_colors.write()[i] = Color(1.0, 1.0, 1.0, 1.0);
420 		mesh_uvs.write()[i] = Vector2(0.0, 0.0);
421 		mesh_vertices.write()[i] = Vector3(0.0, 0.0, 0.0);
422 	}
423 
424 	Array mesh_array;
425 	mesh_array.resize(VS::ARRAY_MAX);
426 	mesh_array[VS::ARRAY_VERTEX] = mesh_vertices;
427 	mesh_array[VS::ARRAY_NORMAL] = mesh_normals;
428 	mesh_array[VS::ARRAY_TANGENT] = mesh_tangents;
429 	mesh_array[VS::ARRAY_COLOR] = mesh_colors;
430 	mesh_array[VS::ARRAY_TEX_UV] = mesh_uvs;
431 
432 	VS::get_singleton()->mesh_add_surface_from_arrays(mesh, VS::PRIMITIVE_TRIANGLE_FAN, mesh_array);
433 	const int surface_vertex_len = VS::get_singleton()->mesh_surface_get_array_len(mesh, 0);
434 	const int surface_index_len = VS::get_singleton()->mesh_surface_get_array_index_len(mesh, 0);
435 
436 	mesh_surface_format = VS::get_singleton()->mesh_surface_get_format(mesh, 0);
437 	mesh_buffer = VS::get_singleton()->mesh_surface_get_array(mesh, 0);
438 	mesh_stride = VS::get_singleton()->mesh_surface_make_offsets_from_format(mesh_surface_format, surface_vertex_len, surface_index_len, mesh_surface_offsets);
439 }
440 
~SpriteBase3D()441 SpriteBase3D::~SpriteBase3D() {
442 
443 	VisualServer::get_singleton()->free(mesh);
444 	VisualServer::get_singleton()->free(material);
445 }
446 
447 ///////////////////////////////////////////
448 
_draw()449 void Sprite3D::_draw() {
450 
451 	set_base(RID());
452 
453 	if (!texture.is_valid())
454 		return;
455 	Vector2 tsize = texture->get_size();
456 	if (tsize.x == 0 || tsize.y == 0)
457 		return;
458 
459 	Rect2 base_rect;
460 	if (region)
461 		base_rect = region_rect;
462 	else
463 		base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
464 
465 	Size2 frame_size = base_rect.size / Size2(hframes, vframes);
466 	Point2 frame_offset = Point2(frame % hframes, frame / hframes);
467 	frame_offset *= frame_size;
468 
469 	Point2 dest_offset = get_offset();
470 	if (is_centered())
471 		dest_offset -= frame_size / 2;
472 
473 	Rect2 src_rect(base_rect.position + frame_offset, frame_size);
474 	Rect2 final_dst_rect(dest_offset, frame_size);
475 	Rect2 final_rect;
476 	Rect2 final_src_rect;
477 	if (!texture->get_rect_region(final_dst_rect, src_rect, final_rect, final_src_rect))
478 		return;
479 
480 	if (final_rect.size.x == 0 || final_rect.size.y == 0)
481 		return;
482 
483 	Color color = _get_color_accum();
484 	color.a *= get_opacity();
485 
486 	float pixel_size = get_pixel_size();
487 
488 	Vector2 vertices[4] = {
489 
490 		(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
491 		(final_rect.position + final_rect.size) * pixel_size,
492 		(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
493 		final_rect.position * pixel_size,
494 
495 	};
496 
497 	Vector2 src_tsize = tsize;
498 
499 	// Properly setup UVs for impostor textures (AtlasTexture).
500 	Ref<AtlasTexture> atlas_tex = texture;
501 	if (atlas_tex != NULL) {
502 		src_tsize[0] = atlas_tex->get_atlas()->get_width();
503 		src_tsize[1] = atlas_tex->get_atlas()->get_height();
504 	}
505 
506 	Vector2 uvs[4] = {
507 		final_src_rect.position / src_tsize,
508 		(final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
509 		(final_src_rect.position + final_src_rect.size) / src_tsize,
510 		(final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
511 	};
512 
513 	if (is_flipped_h()) {
514 		SWAP(uvs[0], uvs[1]);
515 		SWAP(uvs[2], uvs[3]);
516 	}
517 	if (is_flipped_v()) {
518 
519 		SWAP(uvs[0], uvs[3]);
520 		SWAP(uvs[1], uvs[2]);
521 	}
522 
523 	Vector3 normal;
524 	int axis = get_axis();
525 	normal[axis] = 1.0;
526 
527 	Plane tangent;
528 	if (axis == Vector3::AXIS_X) {
529 		tangent = Plane(0, 0, -1, 1);
530 	} else {
531 		tangent = Plane(1, 0, 0, 1);
532 	}
533 
534 	int x_axis = ((axis + 1) % 3);
535 	int y_axis = ((axis + 2) % 3);
536 
537 	if (axis != Vector3::AXIS_Z) {
538 		SWAP(x_axis, y_axis);
539 
540 		for (int i = 0; i < 4; i++) {
541 			//uvs[i] = Vector2(1.0,1.0)-uvs[i];
542 			//SWAP(vertices[i].x,vertices[i].y);
543 			if (axis == Vector3::AXIS_Y) {
544 				vertices[i].y = -vertices[i].y;
545 			} else if (axis == Vector3::AXIS_X) {
546 				vertices[i].x = -vertices[i].x;
547 			}
548 		}
549 	}
550 
551 	AABB aabb;
552 
553 	// Buffer is using default compression, so everything except position is compressed
554 	PoolVector<uint8_t>::Write write_buffer = mesh_buffer.write();
555 
556 	int8_t v_normal[4] = {
557 		(int8_t)CLAMP(normal.x * 127, -128, 127),
558 		(int8_t)CLAMP(normal.y * 127, -128, 127),
559 		(int8_t)CLAMP(normal.z * 127, -128, 127),
560 		0,
561 	};
562 
563 	int8_t v_tangent[4] = {
564 		(int8_t)CLAMP(tangent.normal.x * 127, -128, 127),
565 		(int8_t)CLAMP(tangent.normal.y * 127, -128, 127),
566 		(int8_t)CLAMP(tangent.normal.z * 127, -128, 127),
567 		(int8_t)CLAMP(tangent.d * 127, -128, 127)
568 	};
569 
570 	uint8_t v_color[4] = {
571 		(uint8_t)CLAMP(int(color.r * 255.0), 0, 255),
572 		(uint8_t)CLAMP(int(color.g * 255.0), 0, 255),
573 		(uint8_t)CLAMP(int(color.b * 255.0), 0, 255),
574 		(uint8_t)CLAMP(int(color.a * 255.0), 0, 255)
575 	};
576 
577 	for (int i = 0; i < 4; i++) {
578 		Vector3 vtx;
579 		vtx[x_axis] = vertices[i][0];
580 		vtx[y_axis] = vertices[i][1];
581 		if (i == 0) {
582 			aabb.position = vtx;
583 			aabb.size = Vector3();
584 		} else {
585 			aabb.expand_to(vtx);
586 		}
587 		if (mesh_surface_format & VS::ARRAY_COMPRESS_TEX_UV) {
588 			uint16_t v_uv[2] = { Math::make_half_float(uvs[i].x), Math::make_half_float(uvs[i].y) };
589 			copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TEX_UV]], v_uv, 4);
590 		} else {
591 			float v_uv[2] = { uvs[i].x, uvs[i].y };
592 			copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TEX_UV]], v_uv, 8);
593 		}
594 
595 		float v_vertex[3] = { vtx.x, vtx.y, vtx.z };
596 
597 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
598 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 4);
599 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 4);
600 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_COLOR]], v_color, 4);
601 	}
602 
603 	write_buffer.release();
604 
605 	RID mesh = get_mesh();
606 	VS::get_singleton()->mesh_surface_update_region(mesh, 0, 0, mesh_buffer);
607 
608 	VS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
609 	set_aabb(aabb);
610 
611 	set_base(mesh);
612 
613 	RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y);
614 	VS::get_singleton()->material_set_shader(get_material(), VS::get_singleton()->material_get_shader(mat));
615 	VS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
616 	VS::get_singleton()->instance_set_surface_material(get_instance(), 0, get_material());
617 }
618 
set_texture(const Ref<Texture> & p_texture)619 void Sprite3D::set_texture(const Ref<Texture> &p_texture) {
620 
621 	if (p_texture == texture)
622 		return;
623 	if (texture.is_valid()) {
624 		texture->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_queue_update);
625 	}
626 	texture = p_texture;
627 	if (texture.is_valid()) {
628 		texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
629 		texture->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->_queue_update);
630 	}
631 	_queue_update();
632 }
633 
get_texture() const634 Ref<Texture> Sprite3D::get_texture() const {
635 
636 	return texture;
637 }
638 
set_region(bool p_region)639 void Sprite3D::set_region(bool p_region) {
640 
641 	if (p_region == region)
642 		return;
643 
644 	region = p_region;
645 	_queue_update();
646 }
647 
is_region() const648 bool Sprite3D::is_region() const {
649 
650 	return region;
651 }
652 
set_region_rect(const Rect2 & p_region_rect)653 void Sprite3D::set_region_rect(const Rect2 &p_region_rect) {
654 
655 	bool changed = region_rect != p_region_rect;
656 	region_rect = p_region_rect;
657 	if (region && changed) {
658 		_queue_update();
659 	}
660 }
661 
get_region_rect() const662 Rect2 Sprite3D::get_region_rect() const {
663 
664 	return region_rect;
665 }
666 
set_frame(int p_frame)667 void Sprite3D::set_frame(int p_frame) {
668 
669 	ERR_FAIL_INDEX(p_frame, int64_t(vframes) * hframes);
670 
671 	frame = p_frame;
672 
673 	_queue_update();
674 
675 	_change_notify("frame");
676 	_change_notify("frame_coords");
677 	emit_signal(SceneStringNames::get_singleton()->frame_changed);
678 }
679 
get_frame() const680 int Sprite3D::get_frame() const {
681 
682 	return frame;
683 }
684 
set_frame_coords(const Vector2 & p_coord)685 void Sprite3D::set_frame_coords(const Vector2 &p_coord) {
686 	ERR_FAIL_INDEX(int(p_coord.x), hframes);
687 	ERR_FAIL_INDEX(int(p_coord.y), vframes);
688 
689 	set_frame(int(p_coord.y) * hframes + int(p_coord.x));
690 }
691 
get_frame_coords() const692 Vector2 Sprite3D::get_frame_coords() const {
693 	return Vector2(frame % hframes, frame / hframes);
694 }
695 
set_vframes(int p_amount)696 void Sprite3D::set_vframes(int p_amount) {
697 
698 	ERR_FAIL_COND(p_amount < 1);
699 	vframes = p_amount;
700 	_queue_update();
701 	_change_notify();
702 }
get_vframes() const703 int Sprite3D::get_vframes() const {
704 
705 	return vframes;
706 }
707 
set_hframes(int p_amount)708 void Sprite3D::set_hframes(int p_amount) {
709 
710 	ERR_FAIL_COND(p_amount < 1);
711 	hframes = p_amount;
712 	_queue_update();
713 	_change_notify();
714 }
get_hframes() const715 int Sprite3D::get_hframes() const {
716 
717 	return hframes;
718 }
719 
get_item_rect() const720 Rect2 Sprite3D::get_item_rect() const {
721 
722 	if (texture.is_null())
723 		return Rect2(0, 0, 1, 1);
724 	/*
725 	if (texture.is_null())
726 		return CanvasItem::get_item_rect();
727 	*/
728 
729 	Size2i s;
730 
731 	if (region) {
732 
733 		s = region_rect.size;
734 	} else {
735 		s = texture->get_size();
736 		s = s / Point2(hframes, vframes);
737 	}
738 
739 	Point2 ofs = get_offset();
740 	if (is_centered())
741 		ofs -= s / 2;
742 
743 	if (s == Size2(0, 0))
744 		s = Size2(1, 1);
745 
746 	return Rect2(ofs, s);
747 }
748 
_validate_property(PropertyInfo & property) const749 void Sprite3D::_validate_property(PropertyInfo &property) const {
750 
751 	if (property.name == "frame") {
752 		property.hint = PROPERTY_HINT_RANGE;
753 		property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
754 		property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
755 	}
756 
757 	if (property.name == "frame_coords") {
758 		property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
759 	}
760 }
761 
_bind_methods()762 void Sprite3D::_bind_methods() {
763 
764 	ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite3D::set_texture);
765 	ClassDB::bind_method(D_METHOD("get_texture"), &Sprite3D::get_texture);
766 
767 	ClassDB::bind_method(D_METHOD("set_region", "enabled"), &Sprite3D::set_region);
768 	ClassDB::bind_method(D_METHOD("is_region"), &Sprite3D::is_region);
769 
770 	ClassDB::bind_method(D_METHOD("set_region_rect", "rect"), &Sprite3D::set_region_rect);
771 	ClassDB::bind_method(D_METHOD("get_region_rect"), &Sprite3D::get_region_rect);
772 
773 	ClassDB::bind_method(D_METHOD("set_frame", "frame"), &Sprite3D::set_frame);
774 	ClassDB::bind_method(D_METHOD("get_frame"), &Sprite3D::get_frame);
775 
776 	ClassDB::bind_method(D_METHOD("set_frame_coords", "coords"), &Sprite3D::set_frame_coords);
777 	ClassDB::bind_method(D_METHOD("get_frame_coords"), &Sprite3D::get_frame_coords);
778 
779 	ClassDB::bind_method(D_METHOD("set_vframes", "vframes"), &Sprite3D::set_vframes);
780 	ClassDB::bind_method(D_METHOD("get_vframes"), &Sprite3D::get_vframes);
781 
782 	ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite3D::set_hframes);
783 	ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite3D::get_hframes);
784 
785 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
786 	ADD_GROUP("Animation", "");
787 	ADD_PROPERTY(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_vframes", "get_vframes");
788 	ADD_PROPERTY(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), "set_hframes", "get_hframes");
789 	ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
790 	ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "frame_coords", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_frame_coords", "get_frame_coords");
791 	ADD_GROUP("Region", "region_");
792 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "region_enabled"), "set_region", "is_region");
793 	ADD_PROPERTY(PropertyInfo(Variant::RECT2, "region_rect"), "set_region_rect", "get_region_rect");
794 
795 	ADD_SIGNAL(MethodInfo("frame_changed"));
796 }
797 
Sprite3D()798 Sprite3D::Sprite3D() {
799 
800 	region = false;
801 	frame = 0;
802 	vframes = 1;
803 	hframes = 1;
804 }
805 
806 ////////////////////////////////////////
807 
_draw()808 void AnimatedSprite3D::_draw() {
809 
810 	set_base(RID());
811 
812 	if (frames.is_null()) {
813 		return;
814 	}
815 
816 	if (frame < 0) {
817 		return;
818 	}
819 
820 	if (!frames->has_animation(animation)) {
821 		return;
822 	}
823 
824 	Ref<Texture> texture = frames->get_frame(animation, frame);
825 	if (!texture.is_valid())
826 		return; //no texuture no life
827 	Vector2 tsize = texture->get_size();
828 	if (tsize.x == 0 || tsize.y == 0)
829 		return;
830 
831 	Size2i s = tsize;
832 	Rect2 src_rect;
833 
834 	src_rect.size = s;
835 
836 	Point2 ofs = get_offset();
837 	if (is_centered())
838 		ofs -= s / 2;
839 
840 	Rect2 dst_rect(ofs, s);
841 
842 	Rect2 final_rect;
843 	Rect2 final_src_rect;
844 	if (!texture->get_rect_region(dst_rect, src_rect, final_rect, final_src_rect))
845 		return;
846 
847 	if (final_rect.size.x == 0 || final_rect.size.y == 0)
848 		return;
849 
850 	Color color = _get_color_accum();
851 	color.a *= get_opacity();
852 
853 	float pixel_size = get_pixel_size();
854 
855 	Vector2 vertices[4] = {
856 
857 		(final_rect.position + Vector2(0, final_rect.size.y)) * pixel_size,
858 		(final_rect.position + final_rect.size) * pixel_size,
859 		(final_rect.position + Vector2(final_rect.size.x, 0)) * pixel_size,
860 		final_rect.position * pixel_size,
861 
862 	};
863 
864 	Vector2 src_tsize = tsize;
865 
866 	// Properly setup UVs for impostor textures (AtlasTexture).
867 	Ref<AtlasTexture> atlas_tex = texture;
868 	if (atlas_tex != NULL) {
869 		src_tsize[0] = atlas_tex->get_atlas()->get_width();
870 		src_tsize[1] = atlas_tex->get_atlas()->get_height();
871 	}
872 
873 	Vector2 uvs[4] = {
874 		final_src_rect.position / src_tsize,
875 		(final_src_rect.position + Vector2(final_src_rect.size.x, 0)) / src_tsize,
876 		(final_src_rect.position + final_src_rect.size) / src_tsize,
877 		(final_src_rect.position + Vector2(0, final_src_rect.size.y)) / src_tsize,
878 	};
879 
880 	if (is_flipped_h()) {
881 		SWAP(uvs[0], uvs[1]);
882 		SWAP(uvs[2], uvs[3]);
883 	}
884 	if (is_flipped_v()) {
885 
886 		SWAP(uvs[0], uvs[3]);
887 		SWAP(uvs[1], uvs[2]);
888 	}
889 
890 	Vector3 normal;
891 	int axis = get_axis();
892 	normal[axis] = 1.0;
893 
894 	Plane tangent;
895 	if (axis == Vector3::AXIS_X) {
896 		tangent = Plane(0, 0, -1, -1);
897 	} else {
898 		tangent = Plane(1, 0, 0, -1);
899 	}
900 
901 	int x_axis = ((axis + 1) % 3);
902 	int y_axis = ((axis + 2) % 3);
903 
904 	if (axis != Vector3::AXIS_Z) {
905 		SWAP(x_axis, y_axis);
906 
907 		for (int i = 0; i < 4; i++) {
908 			//uvs[i] = Vector2(1.0,1.0)-uvs[i];
909 			//SWAP(vertices[i].x,vertices[i].y);
910 			if (axis == Vector3::AXIS_Y) {
911 				vertices[i].y = -vertices[i].y;
912 			} else if (axis == Vector3::AXIS_X) {
913 				vertices[i].x = -vertices[i].x;
914 			}
915 		}
916 	}
917 
918 	AABB aabb;
919 
920 	// Buffer is using default compression, so everything except position is compressed
921 	PoolVector<uint8_t>::Write write_buffer = mesh_buffer.write();
922 
923 	int8_t v_normal[4] = {
924 		(int8_t)CLAMP(normal.x * 127, -128, 127),
925 		(int8_t)CLAMP(normal.y * 127, -128, 127),
926 		(int8_t)CLAMP(normal.z * 127, -128, 127),
927 		0,
928 	};
929 
930 	int8_t v_tangent[4] = {
931 		(int8_t)CLAMP(tangent.normal.x * 127, -128, 127),
932 		(int8_t)CLAMP(tangent.normal.y * 127, -128, 127),
933 		(int8_t)CLAMP(tangent.normal.z * 127, -128, 127),
934 		(int8_t)CLAMP(tangent.d * 127, -128, 127)
935 	};
936 
937 	uint8_t v_color[4] = {
938 		(uint8_t)CLAMP(int(color.r * 255.0), 0, 255),
939 		(uint8_t)CLAMP(int(color.g * 255.0), 0, 255),
940 		(uint8_t)CLAMP(int(color.b * 255.0), 0, 255),
941 		(uint8_t)CLAMP(int(color.a * 255.0), 0, 255)
942 	};
943 
944 	for (int i = 0; i < 4; i++) {
945 		Vector3 vtx;
946 		vtx[x_axis] = vertices[i][0];
947 		vtx[y_axis] = vertices[i][1];
948 		if (i == 0) {
949 			aabb.position = vtx;
950 			aabb.size = Vector3();
951 		} else {
952 			aabb.expand_to(vtx);
953 		}
954 
955 		if (mesh_surface_format & VS::ARRAY_COMPRESS_TEX_UV) {
956 			uint16_t v_uv[2] = { Math::make_half_float(uvs[i].x), Math::make_half_float(uvs[i].y) };
957 			copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TEX_UV]], v_uv, 4);
958 		} else {
959 			float v_uv[2] = { uvs[i].x, uvs[i].y };
960 			copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TEX_UV]], v_uv, 8);
961 		}
962 		float v_vertex[3] = { vtx.x, vtx.y, vtx.z };
963 
964 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_VERTEX]], &v_vertex, sizeof(float) * 3);
965 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_NORMAL]], v_normal, 4);
966 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_TANGENT]], v_tangent, 4);
967 		copymem(&write_buffer[i * mesh_stride + mesh_surface_offsets[VS::ARRAY_COLOR]], v_color, 4);
968 	}
969 
970 	write_buffer.release();
971 
972 	RID mesh = get_mesh();
973 	VS::get_singleton()->mesh_surface_update_region(mesh, 0, 0, mesh_buffer);
974 
975 	VS::get_singleton()->mesh_set_custom_aabb(mesh, aabb);
976 	set_aabb(aabb);
977 
978 	set_base(mesh);
979 
980 	RID mat = SpatialMaterial::get_material_rid_for_2d(get_draw_flag(FLAG_SHADED), get_draw_flag(FLAG_TRANSPARENT), get_draw_flag(FLAG_DOUBLE_SIDED), get_alpha_cut_mode() == ALPHA_CUT_DISCARD, get_alpha_cut_mode() == ALPHA_CUT_OPAQUE_PREPASS, get_billboard_mode() == SpatialMaterial::BILLBOARD_ENABLED, get_billboard_mode() == SpatialMaterial::BILLBOARD_FIXED_Y);
981 	VS::get_singleton()->material_set_shader(get_material(), VS::get_singleton()->material_get_shader(mat));
982 	VS::get_singleton()->material_set_param(get_material(), "texture_albedo", texture->get_rid());
983 	VS::get_singleton()->instance_set_surface_material(get_instance(), 0, get_material());
984 }
985 
_validate_property(PropertyInfo & property) const986 void AnimatedSprite3D::_validate_property(PropertyInfo &property) const {
987 
988 	if (!frames.is_valid())
989 		return;
990 	if (property.name == "animation") {
991 
992 		property.hint = PROPERTY_HINT_ENUM;
993 		List<StringName> names;
994 		frames->get_animation_list(&names);
995 		names.sort_custom<StringName::AlphCompare>();
996 
997 		bool current_found = false;
998 
999 		for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
1000 			if (E->prev()) {
1001 				property.hint_string += ",";
1002 			}
1003 
1004 			property.hint_string += String(E->get());
1005 			if (animation == E->get()) {
1006 				current_found = true;
1007 			}
1008 		}
1009 
1010 		if (!current_found) {
1011 			if (property.hint_string == String()) {
1012 				property.hint_string = String(animation);
1013 			} else {
1014 				property.hint_string = String(animation) + "," + property.hint_string;
1015 			}
1016 		}
1017 	}
1018 
1019 	if (property.name == "frame") {
1020 		property.hint = PROPERTY_HINT_RANGE;
1021 		if (frames->has_animation(animation) && frames->get_frame_count(animation) > 1) {
1022 			property.hint_string = "0," + itos(frames->get_frame_count(animation) - 1) + ",1";
1023 		}
1024 		property.usage |= PROPERTY_USAGE_KEYING_INCREMENTS;
1025 	}
1026 }
1027 
_notification(int p_what)1028 void AnimatedSprite3D::_notification(int p_what) {
1029 
1030 	switch (p_what) {
1031 		case NOTIFICATION_INTERNAL_PROCESS: {
1032 
1033 			if (frames.is_null())
1034 				return;
1035 			if (!frames->has_animation(animation))
1036 				return;
1037 			if (frame < 0)
1038 				return;
1039 
1040 			float speed = frames->get_animation_speed(animation);
1041 			if (speed == 0)
1042 				return; //do nothing
1043 
1044 			float remaining = get_process_delta_time();
1045 
1046 			while (remaining) {
1047 
1048 				if (timeout <= 0) {
1049 
1050 					timeout = 1.0 / speed;
1051 
1052 					int fc = frames->get_frame_count(animation);
1053 					if (frame >= fc - 1) {
1054 						if (frames->get_animation_loop(animation)) {
1055 							frame = 0;
1056 						} else {
1057 							frame = fc - 1;
1058 						}
1059 					} else {
1060 						frame++;
1061 					}
1062 
1063 					_queue_update();
1064 					_change_notify("frame");
1065 				}
1066 
1067 				float to_process = MIN(timeout, remaining);
1068 				remaining -= to_process;
1069 				timeout -= to_process;
1070 			}
1071 		} break;
1072 	}
1073 }
1074 
set_sprite_frames(const Ref<SpriteFrames> & p_frames)1075 void AnimatedSprite3D::set_sprite_frames(const Ref<SpriteFrames> &p_frames) {
1076 
1077 	if (frames.is_valid())
1078 		frames->disconnect("changed", this, "_res_changed");
1079 	frames = p_frames;
1080 	if (frames.is_valid())
1081 		frames->connect("changed", this, "_res_changed");
1082 
1083 	if (!frames.is_valid()) {
1084 		frame = 0;
1085 	} else {
1086 		set_frame(frame);
1087 	}
1088 
1089 	_change_notify();
1090 	_reset_timeout();
1091 	_queue_update();
1092 	update_configuration_warning();
1093 }
1094 
get_sprite_frames() const1095 Ref<SpriteFrames> AnimatedSprite3D::get_sprite_frames() const {
1096 
1097 	return frames;
1098 }
1099 
set_frame(int p_frame)1100 void AnimatedSprite3D::set_frame(int p_frame) {
1101 
1102 	if (!frames.is_valid()) {
1103 		return;
1104 	}
1105 
1106 	if (frames->has_animation(animation)) {
1107 		int limit = frames->get_frame_count(animation);
1108 		if (p_frame >= limit)
1109 			p_frame = limit - 1;
1110 	}
1111 
1112 	if (p_frame < 0)
1113 		p_frame = 0;
1114 
1115 	if (frame == p_frame)
1116 		return;
1117 
1118 	frame = p_frame;
1119 	_reset_timeout();
1120 	_queue_update();
1121 	_change_notify("frame");
1122 	emit_signal(SceneStringNames::get_singleton()->frame_changed);
1123 }
get_frame() const1124 int AnimatedSprite3D::get_frame() const {
1125 
1126 	return frame;
1127 }
1128 
get_item_rect() const1129 Rect2 AnimatedSprite3D::get_item_rect() const {
1130 
1131 	if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
1132 		return Rect2(0, 0, 1, 1);
1133 	}
1134 
1135 	Ref<Texture> t;
1136 	if (animation)
1137 		t = frames->get_frame(animation, frame);
1138 	if (t.is_null())
1139 		return Rect2(0, 0, 1, 1);
1140 	Size2i s = t->get_size();
1141 
1142 	Point2 ofs = get_offset();
1143 	if (centered)
1144 		ofs -= s / 2;
1145 
1146 	if (s == Size2(0, 0))
1147 		s = Size2(1, 1);
1148 
1149 	return Rect2(ofs, s);
1150 }
1151 
_res_changed()1152 void AnimatedSprite3D::_res_changed() {
1153 
1154 	set_frame(frame);
1155 	_change_notify("frame");
1156 	_change_notify("animation");
1157 	_queue_update();
1158 }
1159 
_set_playing(bool p_playing)1160 void AnimatedSprite3D::_set_playing(bool p_playing) {
1161 
1162 	if (playing == p_playing)
1163 		return;
1164 	playing = p_playing;
1165 	_reset_timeout();
1166 	set_process_internal(playing);
1167 }
1168 
_is_playing() const1169 bool AnimatedSprite3D::_is_playing() const {
1170 
1171 	return playing;
1172 }
1173 
play(const StringName & p_animation)1174 void AnimatedSprite3D::play(const StringName &p_animation) {
1175 
1176 	if (p_animation)
1177 		set_animation(p_animation);
1178 	_set_playing(true);
1179 }
1180 
stop()1181 void AnimatedSprite3D::stop() {
1182 
1183 	_set_playing(false);
1184 }
1185 
is_playing() const1186 bool AnimatedSprite3D::is_playing() const {
1187 
1188 	return is_processing();
1189 }
1190 
_reset_timeout()1191 void AnimatedSprite3D::_reset_timeout() {
1192 
1193 	if (!playing)
1194 		return;
1195 
1196 	if (frames.is_valid() && frames->has_animation(animation)) {
1197 		float speed = frames->get_animation_speed(animation);
1198 		if (speed > 0) {
1199 			timeout = 1.0 / speed;
1200 		} else {
1201 			timeout = 0;
1202 		}
1203 	} else {
1204 		timeout = 0;
1205 	}
1206 }
1207 
set_animation(const StringName & p_animation)1208 void AnimatedSprite3D::set_animation(const StringName &p_animation) {
1209 
1210 	if (animation == p_animation)
1211 		return;
1212 
1213 	animation = p_animation;
1214 	_reset_timeout();
1215 	set_frame(0);
1216 	_change_notify();
1217 	_queue_update();
1218 }
get_animation() const1219 StringName AnimatedSprite3D::get_animation() const {
1220 
1221 	return animation;
1222 }
1223 
get_configuration_warning() const1224 String AnimatedSprite3D::get_configuration_warning() const {
1225 
1226 	if (frames.is_null()) {
1227 		return TTR("A SpriteFrames resource must be created or set in the \"Frames\" property in order for AnimatedSprite3D to display frames.");
1228 	}
1229 
1230 	return String();
1231 }
1232 
_bind_methods()1233 void AnimatedSprite3D::_bind_methods() {
1234 
1235 	ClassDB::bind_method(D_METHOD("set_sprite_frames", "sprite_frames"), &AnimatedSprite3D::set_sprite_frames);
1236 	ClassDB::bind_method(D_METHOD("get_sprite_frames"), &AnimatedSprite3D::get_sprite_frames);
1237 
1238 	ClassDB::bind_method(D_METHOD("set_animation", "animation"), &AnimatedSprite3D::set_animation);
1239 	ClassDB::bind_method(D_METHOD("get_animation"), &AnimatedSprite3D::get_animation);
1240 
1241 	ClassDB::bind_method(D_METHOD("_set_playing", "playing"), &AnimatedSprite3D::_set_playing);
1242 	ClassDB::bind_method(D_METHOD("_is_playing"), &AnimatedSprite3D::_is_playing);
1243 
1244 	ClassDB::bind_method(D_METHOD("play", "anim"), &AnimatedSprite3D::play, DEFVAL(StringName()));
1245 	ClassDB::bind_method(D_METHOD("stop"), &AnimatedSprite3D::stop);
1246 	ClassDB::bind_method(D_METHOD("is_playing"), &AnimatedSprite3D::is_playing);
1247 
1248 	ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite3D::set_frame);
1249 	ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite3D::get_frame);
1250 
1251 	ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite3D::_res_changed);
1252 
1253 	ADD_SIGNAL(MethodInfo("frame_changed"));
1254 
1255 	ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
1256 	ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
1257 	ADD_PROPERTY(PropertyInfo(Variant::INT, "frame"), "set_frame", "get_frame");
1258 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
1259 }
1260 
AnimatedSprite3D()1261 AnimatedSprite3D::AnimatedSprite3D() {
1262 
1263 	frame = 0;
1264 	playing = false;
1265 	animation = "default";
1266 	timeout = 0;
1267 }
1268