1 /*************************************************************************/
2 /*  sprite.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 "sprite.h"
31 #include "core/core_string_names.h"
32 #include "os/os.h"
33 #include "scene/main/viewport.h"
34 #include "scene/scene_string_names.h"
35 
edit_set_pivot(const Point2 & p_pivot)36 void Sprite::edit_set_pivot(const Point2 &p_pivot) {
37 
38 	set_offset(p_pivot);
39 }
40 
edit_get_pivot() const41 Point2 Sprite::edit_get_pivot() const {
42 
43 	return get_offset();
44 }
edit_has_pivot() const45 bool Sprite::edit_has_pivot() const {
46 
47 	return true;
48 }
49 
_notification(int p_what)50 void Sprite::_notification(int p_what) {
51 
52 	switch (p_what) {
53 
54 		case NOTIFICATION_DRAW: {
55 
56 			if (texture.is_null())
57 				return;
58 
59 			RID ci = get_canvas_item();
60 
61 			/*
62 			texture->draw(ci,Point2());
63 			break;
64 			*/
65 
66 			Size2 s;
67 			Rect2 src_rect;
68 
69 			if (region) {
70 
71 				s = region_rect.size;
72 				src_rect = region_rect;
73 			} else {
74 				s = Size2(texture->get_size());
75 				s = s / Size2(hframes, vframes);
76 
77 				src_rect.size = s;
78 				src_rect.pos.x += float(frame % hframes) * s.x;
79 				src_rect.pos.y += float(frame / hframes) * s.y;
80 			}
81 
82 			Point2 ofs = offset;
83 			if (centered)
84 				ofs -= s / 2;
85 			if (OS::get_singleton()->get_use_pixel_snap()) {
86 				ofs = ofs.floor();
87 			}
88 
89 			Rect2 dst_rect(ofs, s);
90 
91 			if (hflip)
92 				dst_rect.size.x = -dst_rect.size.x;
93 			if (vflip)
94 				dst_rect.size.y = -dst_rect.size.y;
95 
96 			texture->draw_rect_region(ci, dst_rect, src_rect, modulate);
97 
98 		} break;
99 	}
100 }
101 
set_texture(const Ref<Texture> & p_texture)102 void Sprite::set_texture(const Ref<Texture> &p_texture) {
103 
104 	if (p_texture == texture)
105 		return;
106 #ifdef DEBUG_ENABLED
107 	if (texture.is_valid()) {
108 		texture->disconnect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->update);
109 	}
110 #endif
111 	texture = p_texture;
112 #ifdef DEBUG_ENABLED
113 	if (texture.is_valid()) {
114 		texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
115 		texture->connect(CoreStringNames::get_singleton()->changed, this, SceneStringNames::get_singleton()->update);
116 	}
117 #endif
118 	update();
119 	emit_signal("texture_changed");
120 	item_rect_changed();
121 }
122 
get_texture() const123 Ref<Texture> Sprite::get_texture() const {
124 
125 	return texture;
126 }
127 
set_centered(bool p_center)128 void Sprite::set_centered(bool p_center) {
129 
130 	centered = p_center;
131 	update();
132 	item_rect_changed();
133 }
134 
is_centered() const135 bool Sprite::is_centered() const {
136 
137 	return centered;
138 }
139 
set_offset(const Point2 & p_offset)140 void Sprite::set_offset(const Point2 &p_offset) {
141 
142 	offset = p_offset;
143 	update();
144 	item_rect_changed();
145 	_change_notify("offset");
146 }
get_offset() const147 Point2 Sprite::get_offset() const {
148 
149 	return offset;
150 }
151 
set_flip_h(bool p_flip)152 void Sprite::set_flip_h(bool p_flip) {
153 
154 	hflip = p_flip;
155 	update();
156 }
is_flipped_h() const157 bool Sprite::is_flipped_h() const {
158 
159 	return hflip;
160 }
161 
set_flip_v(bool p_flip)162 void Sprite::set_flip_v(bool p_flip) {
163 
164 	vflip = p_flip;
165 	update();
166 }
is_flipped_v() const167 bool Sprite::is_flipped_v() const {
168 
169 	return vflip;
170 }
171 
set_region(bool p_region)172 void Sprite::set_region(bool p_region) {
173 
174 	if (p_region == region)
175 		return;
176 
177 	region = p_region;
178 	update();
179 }
180 
is_region() const181 bool Sprite::is_region() const {
182 
183 	return region;
184 }
185 
set_region_rect(const Rect2 & p_region_rect)186 void Sprite::set_region_rect(const Rect2 &p_region_rect) {
187 
188 	if (region_rect == p_region_rect)
189 		return;
190 
191 	region_rect = p_region_rect;
192 
193 	if (region)
194 		item_rect_changed();
195 
196 	_change_notify("region_rect");
197 }
198 
get_region_rect() const199 Rect2 Sprite::get_region_rect() const {
200 
201 	return region_rect;
202 }
203 
set_frame(int p_frame)204 void Sprite::set_frame(int p_frame) {
205 
206 	ERR_FAIL_INDEX(p_frame, vframes * hframes);
207 
208 	if (frame != p_frame)
209 		item_rect_changed();
210 
211 	frame = p_frame;
212 
213 	_change_notify("frame");
214 	emit_signal(SceneStringNames::get_singleton()->frame_changed);
215 }
216 
get_frame() const217 int Sprite::get_frame() const {
218 
219 	return frame;
220 }
221 
set_vframes(int p_amount)222 void Sprite::set_vframes(int p_amount) {
223 
224 	ERR_FAIL_COND(p_amount < 1);
225 	vframes = p_amount;
226 	update();
227 	item_rect_changed();
228 	_change_notify();
229 }
get_vframes() const230 int Sprite::get_vframes() const {
231 
232 	return vframes;
233 }
234 
set_hframes(int p_amount)235 void Sprite::set_hframes(int p_amount) {
236 
237 	ERR_FAIL_COND(p_amount < 1);
238 	hframes = p_amount;
239 	update();
240 	item_rect_changed();
241 	_change_notify();
242 }
get_hframes() const243 int Sprite::get_hframes() const {
244 
245 	return hframes;
246 }
247 
set_modulate(const Color & p_color)248 void Sprite::set_modulate(const Color &p_color) {
249 
250 	modulate = p_color;
251 	update();
252 }
253 
get_modulate() const254 Color Sprite::get_modulate() const {
255 
256 	return modulate;
257 }
258 
get_item_rect() const259 Rect2 Sprite::get_item_rect() const {
260 
261 	if (texture.is_null())
262 		return Rect2(0, 0, 1, 1);
263 	//if (texture.is_null())
264 	//	return CanvasItem::get_item_rect();
265 
266 	Size2i s;
267 
268 	if (region) {
269 
270 		s = region_rect.size;
271 	} else {
272 		s = texture->get_size();
273 		s = s / Point2(hframes, vframes);
274 	}
275 
276 	Point2 ofs = offset;
277 	if (centered)
278 		ofs -= s / 2;
279 
280 	if (s == Size2(0, 0))
281 		s = Size2(1, 1);
282 
283 	return Rect2(ofs, s);
284 }
285 
_validate_property(PropertyInfo & property) const286 void Sprite::_validate_property(PropertyInfo &property) const {
287 
288 	if (property.name == "frame") {
289 
290 		property.hint = PROPERTY_HINT_SPRITE_FRAME;
291 
292 		property.hint_string = "0," + itos(vframes * hframes - 1) + ",1";
293 	}
294 }
295 
_bind_methods()296 void Sprite::_bind_methods() {
297 
298 	ObjectTypeDB::bind_method(_MD("set_texture", "texture:Texture"), &Sprite::set_texture);
299 	ObjectTypeDB::bind_method(_MD("get_texture:Texture"), &Sprite::get_texture);
300 
301 	ObjectTypeDB::bind_method(_MD("set_centered", "centered"), &Sprite::set_centered);
302 	ObjectTypeDB::bind_method(_MD("is_centered"), &Sprite::is_centered);
303 
304 	ObjectTypeDB::bind_method(_MD("set_offset", "offset"), &Sprite::set_offset);
305 	ObjectTypeDB::bind_method(_MD("get_offset"), &Sprite::get_offset);
306 
307 	ObjectTypeDB::bind_method(_MD("set_flip_h", "flip_h"), &Sprite::set_flip_h);
308 	ObjectTypeDB::bind_method(_MD("is_flipped_h"), &Sprite::is_flipped_h);
309 
310 	ObjectTypeDB::bind_method(_MD("set_flip_v", "flip_v"), &Sprite::set_flip_v);
311 	ObjectTypeDB::bind_method(_MD("is_flipped_v"), &Sprite::is_flipped_v);
312 
313 	ObjectTypeDB::bind_method(_MD("set_region", "enabled"), &Sprite::set_region);
314 	ObjectTypeDB::bind_method(_MD("is_region"), &Sprite::is_region);
315 
316 	ObjectTypeDB::bind_method(_MD("set_region_rect", "rect"), &Sprite::set_region_rect);
317 	ObjectTypeDB::bind_method(_MD("get_region_rect"), &Sprite::get_region_rect);
318 
319 	ObjectTypeDB::bind_method(_MD("set_frame", "frame"), &Sprite::set_frame);
320 	ObjectTypeDB::bind_method(_MD("get_frame"), &Sprite::get_frame);
321 
322 	ObjectTypeDB::bind_method(_MD("set_vframes", "vframes"), &Sprite::set_vframes);
323 	ObjectTypeDB::bind_method(_MD("get_vframes"), &Sprite::get_vframes);
324 
325 	ObjectTypeDB::bind_method(_MD("set_hframes", "hframes"), &Sprite::set_hframes);
326 	ObjectTypeDB::bind_method(_MD("get_hframes"), &Sprite::get_hframes);
327 
328 	ObjectTypeDB::bind_method(_MD("set_modulate", "modulate"), &Sprite::set_modulate);
329 	ObjectTypeDB::bind_method(_MD("get_modulate"), &Sprite::get_modulate);
330 
331 	ADD_SIGNAL(MethodInfo("frame_changed"));
332 	ADD_SIGNAL(MethodInfo("texture_changed"));
333 
334 	ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"), _SCS("get_texture"));
335 	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), _SCS("set_centered"), _SCS("is_centered"));
336 	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), _SCS("set_offset"), _SCS("get_offset"));
337 	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_h"), _SCS("set_flip_h"), _SCS("is_flipped_h"));
338 	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "flip_v"), _SCS("set_flip_v"), _SCS("is_flipped_v"));
339 	ADD_PROPERTYNO(PropertyInfo(Variant::INT, "vframes", PROPERTY_HINT_RANGE, "1,16384,1"), _SCS("set_vframes"), _SCS("get_vframes"));
340 	ADD_PROPERTYNO(PropertyInfo(Variant::INT, "hframes", PROPERTY_HINT_RANGE, "1,16384,1"), _SCS("set_hframes"), _SCS("get_hframes"));
341 	ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"), _SCS("get_frame"));
342 	ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
343 	ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "region"), _SCS("set_region"), _SCS("is_region"));
344 	ADD_PROPERTYNZ(PropertyInfo(Variant::RECT2, "region_rect"), _SCS("set_region_rect"), _SCS("get_region_rect"));
345 }
346 
Sprite()347 Sprite::Sprite() {
348 
349 	centered = true;
350 	hflip = false;
351 	vflip = false;
352 	region = false;
353 
354 	frame = 0;
355 
356 	vframes = 1;
357 	hframes = 1;
358 
359 	modulate = Color(1, 1, 1, 1);
360 }
361 
362 //////////////////////////// VPSPRITE
363 ///
364 ///
365 ///
366 
edit_set_pivot(const Point2 & p_pivot)367 void ViewportSprite::edit_set_pivot(const Point2 &p_pivot) {
368 
369 	set_offset(p_pivot);
370 }
371 
edit_get_pivot() const372 Point2 ViewportSprite::edit_get_pivot() const {
373 
374 	return get_offset();
375 }
edit_has_pivot() const376 bool ViewportSprite::edit_has_pivot() const {
377 
378 	return true;
379 }
380 
_notification(int p_what)381 void ViewportSprite::_notification(int p_what) {
382 
383 	switch (p_what) {
384 
385 		case NOTIFICATION_ENTER_TREE: {
386 
387 			if (!viewport_path.is_empty()) {
388 
389 				Node *n = get_node(viewport_path);
390 				ERR_FAIL_COND(!n);
391 				Viewport *vp = n->cast_to<Viewport>();
392 				ERR_FAIL_COND(!vp);
393 
394 				Ref<RenderTargetTexture> rtt = vp->get_render_target_texture();
395 				texture = rtt;
396 				texture->connect("changed", this, "update");
397 				item_rect_changed();
398 			}
399 		} break;
400 		case NOTIFICATION_EXIT_TREE: {
401 
402 			if (texture.is_valid()) {
403 
404 				texture->disconnect("changed", this, "update");
405 				texture = Ref<Texture>();
406 			}
407 		} break;
408 		case NOTIFICATION_DRAW: {
409 
410 			if (texture.is_null())
411 				return;
412 
413 			RID ci = get_canvas_item();
414 
415 			/*
416 			texture->draw(ci,Point2());
417 			break;
418 			*/
419 
420 			Size2i s;
421 			Rect2i src_rect;
422 
423 			s = texture->get_size();
424 
425 			src_rect.size = s;
426 
427 			Point2 ofs = offset;
428 			if (centered)
429 				ofs -= s / 2;
430 
431 			if (OS::get_singleton()->get_use_pixel_snap()) {
432 				ofs = ofs.floor();
433 			}
434 			Rect2 dst_rect(ofs, s);
435 			texture->draw_rect_region(ci, dst_rect, src_rect, modulate);
436 
437 		} break;
438 	}
439 }
440 
set_viewport_path(const NodePath & p_viewport)441 void ViewportSprite::set_viewport_path(const NodePath &p_viewport) {
442 
443 	viewport_path = p_viewport;
444 	update();
445 	if (!is_inside_tree())
446 		return;
447 
448 	if (texture.is_valid()) {
449 		texture->disconnect("changed", this, "update");
450 		texture = Ref<Texture>();
451 	}
452 
453 	if (viewport_path.is_empty())
454 		return;
455 
456 	Node *n = get_node(viewport_path);
457 	ERR_FAIL_COND(!n);
458 	Viewport *vp = n->cast_to<Viewport>();
459 	ERR_FAIL_COND(!vp);
460 
461 	Ref<RenderTargetTexture> rtt = vp->get_render_target_texture();
462 	texture = rtt;
463 
464 	if (texture.is_valid()) {
465 		texture->connect("changed", this, "update");
466 	}
467 
468 	item_rect_changed();
469 }
470 
get_viewport_path() const471 NodePath ViewportSprite::get_viewport_path() const {
472 
473 	return viewport_path;
474 }
475 
set_centered(bool p_center)476 void ViewportSprite::set_centered(bool p_center) {
477 
478 	centered = p_center;
479 	update();
480 	item_rect_changed();
481 }
482 
is_centered() const483 bool ViewportSprite::is_centered() const {
484 
485 	return centered;
486 }
487 
set_offset(const Point2 & p_offset)488 void ViewportSprite::set_offset(const Point2 &p_offset) {
489 
490 	offset = p_offset;
491 	update();
492 	item_rect_changed();
493 }
get_offset() const494 Point2 ViewportSprite::get_offset() const {
495 
496 	return offset;
497 }
set_modulate(const Color & p_color)498 void ViewportSprite::set_modulate(const Color &p_color) {
499 
500 	modulate = p_color;
501 	update();
502 }
503 
get_modulate() const504 Color ViewportSprite::get_modulate() const {
505 
506 	return modulate;
507 }
508 
get_item_rect() const509 Rect2 ViewportSprite::get_item_rect() const {
510 
511 	if (texture.is_null())
512 		return Rect2(0, 0, 1, 1);
513 	//if (texture.is_null())
514 	//	return CanvasItem::get_item_rect();
515 
516 	Size2i s;
517 
518 	s = texture->get_size();
519 	Point2 ofs = offset;
520 	if (centered)
521 		ofs -= s / 2;
522 
523 	if (s == Size2(0, 0))
524 		s = Size2(1, 1);
525 
526 	return Rect2(ofs, s);
527 }
528 
get_configuration_warning() const529 String ViewportSprite::get_configuration_warning() const {
530 
531 	if (!has_node(viewport_path) || !get_node(viewport_path) || !get_node(viewport_path)->cast_to<Viewport>()) {
532 		return TTR("Path property must point to a valid Viewport node to work. Such Viewport must be set to 'render target' mode.");
533 	} else {
534 
535 		Node *n = get_node(viewport_path);
536 		if (n) {
537 			Viewport *vp = n->cast_to<Viewport>();
538 			if (!vp->is_set_as_render_target()) {
539 
540 				return TTR("The Viewport set in the path property must be set as 'render target' in order for this sprite to work.");
541 			}
542 		}
543 	}
544 
545 	return String();
546 }
547 
_bind_methods()548 void ViewportSprite::_bind_methods() {
549 
550 	ObjectTypeDB::bind_method(_MD("set_viewport_path", "path"), &ViewportSprite::set_viewport_path);
551 	ObjectTypeDB::bind_method(_MD("get_viewport_path"), &ViewportSprite::get_viewport_path);
552 
553 	ObjectTypeDB::bind_method(_MD("set_centered", "centered"), &ViewportSprite::set_centered);
554 	ObjectTypeDB::bind_method(_MD("is_centered"), &ViewportSprite::is_centered);
555 
556 	ObjectTypeDB::bind_method(_MD("set_offset", "offset"), &ViewportSprite::set_offset);
557 	ObjectTypeDB::bind_method(_MD("get_offset"), &ViewportSprite::get_offset);
558 
559 	ObjectTypeDB::bind_method(_MD("set_modulate", "modulate"), &ViewportSprite::set_modulate);
560 	ObjectTypeDB::bind_method(_MD("get_modulate"), &ViewportSprite::get_modulate);
561 
562 	ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"), _SCS("get_viewport_path"));
563 	ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), _SCS("set_centered"), _SCS("is_centered"));
564 	ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), _SCS("set_offset"), _SCS("get_offset"));
565 	ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "modulate"), _SCS("set_modulate"), _SCS("get_modulate"));
566 }
567 
ViewportSprite()568 ViewportSprite::ViewportSprite() {
569 
570 	centered = true;
571 	modulate = Color(1, 1, 1, 1);
572 }
573