virtualx-engine/scene/2d/sprite.cpp
Rémi Verschelde d8223ffa75 Welcome in 2017, dear changelog reader!
That year should bring the long-awaited OpenGL ES 3.0 compatible renderer
with state-of-the-art rendering techniques tuned to work as low as middle
end handheld devices - without compromising with the possibilities given
for higher end desktop games of course. Great times ahead for the Godot
community and the gamers that will play our games!

(cherry picked from commit c7bc44d5ad)
2017-01-12 19:15:30 +01:00

591 lines
14 KiB
C++

/*************************************************************************/
/* sprite.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "sprite.h"
#include "core/core_string_names.h"
#include "scene/scene_string_names.h"
#include "scene/main/viewport.h"
#include "os/os.h"
void Sprite::edit_set_pivot(const Point2& p_pivot) {
set_offset(p_pivot);
}
Point2 Sprite::edit_get_pivot() const {
return get_offset();
}
bool Sprite::edit_has_pivot() const {
return true;
}
void Sprite::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_DRAW: {
if (texture.is_null())
return;
RID ci = get_canvas_item();
/*
texture->draw(ci,Point2());
break;
*/
Size2 s;
Rect2 src_rect;
if (region) {
s=region_rect.size;
src_rect=region_rect;
} else {
s = Size2(texture->get_size());
s=s/Size2(hframes,vframes);
src_rect.size=s;
src_rect.pos.x+=float(frame%hframes)*s.x;
src_rect.pos.y+=float(frame/hframes)*s.y;
}
Point2 ofs=offset;
if (centered)
ofs-=s/2;
if (OS::get_singleton()->get_use_pixel_snap()) {
ofs=ofs.floor();
}
Rect2 dst_rect(ofs,s);
if (hflip)
dst_rect.size.x=-dst_rect.size.x;
if (vflip)
dst_rect.size.y=-dst_rect.size.y;
texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
} break;
}
}
void Sprite::set_texture(const Ref<Texture>& p_texture) {
if (p_texture==texture)
return;
#ifdef DEBUG_ENABLED
if (texture.is_valid()) {
texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
}
#endif
texture=p_texture;
#ifdef DEBUG_ENABLED
if (texture.is_valid()) {
texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites
texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update);
}
#endif
update();
emit_signal("texture_changed");
item_rect_changed();
}
Ref<Texture> Sprite::get_texture() const {
return texture;
}
void Sprite::set_centered(bool p_center) {
centered=p_center;
update();
item_rect_changed();
}
bool Sprite::is_centered() const {
return centered;
}
void Sprite::set_offset(const Point2& p_offset) {
offset=p_offset;
update();
item_rect_changed();
_change_notify("offset");
}
Point2 Sprite::get_offset() const {
return offset;
}
void Sprite::set_flip_h(bool p_flip) {
hflip=p_flip;
update();
}
bool Sprite::is_flipped_h() const {
return hflip;
}
void Sprite::set_flip_v(bool p_flip) {
vflip=p_flip;
update();
}
bool Sprite::is_flipped_v() const {
return vflip;
}
void Sprite::set_region(bool p_region) {
if (p_region==region)
return;
region=p_region;
update();
}
bool Sprite::is_region() const{
return region;
}
void Sprite::set_region_rect(const Rect2& p_region_rect) {
if (region_rect==p_region_rect)
return;
region_rect=p_region_rect;
if (region)
item_rect_changed();
_change_notify("region_rect");
}
Rect2 Sprite::get_region_rect() const {
return region_rect;
}
void Sprite::set_frame(int p_frame) {
ERR_FAIL_INDEX(p_frame,vframes*hframes);
if (frame != p_frame)
item_rect_changed();
frame=p_frame;
_change_notify("frame");
emit_signal(SceneStringNames::get_singleton()->frame_changed);
}
int Sprite::get_frame() const {
return frame;
}
void Sprite::set_vframes(int p_amount) {
ERR_FAIL_COND(p_amount<1);
vframes=p_amount;
update();
item_rect_changed();
_change_notify("frame");
}
int Sprite::get_vframes() const {
return vframes;
}
void Sprite::set_hframes(int p_amount) {
ERR_FAIL_COND(p_amount<1);
hframes=p_amount;
update();
item_rect_changed();
_change_notify("frame");
}
int Sprite::get_hframes() const {
return hframes;
}
void Sprite::set_modulate(const Color& p_color) {
modulate=p_color;
update();
}
Color Sprite::get_modulate() const{
return modulate;
}
Rect2 Sprite::get_item_rect() const {
if (texture.is_null())
return Rect2(0,0,1,1);
//if (texture.is_null())
// return CanvasItem::get_item_rect();
Size2i s;
if (region) {
s=region_rect.size;
} else {
s = texture->get_size();
s=s/Point2(hframes,vframes);
}
Point2 ofs=offset;
if (centered)
ofs-=s/2;
if (s==Size2(0,0))
s=Size2(1,1);
return Rect2(ofs,s);
}
void Sprite::_validate_property(PropertyInfo& property) const {
if (property.name=="frame") {
property.hint=PROPERTY_HINT_SPRITE_FRAME;
property.hint_string="0,"+itos(vframes*hframes-1)+",1";
}
}
void Sprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_texture","texture:Texture"),&Sprite::set_texture);
ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&Sprite::get_texture);
ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Sprite::set_centered);
ObjectTypeDB::bind_method(_MD("is_centered"),&Sprite::is_centered);
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Sprite::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&Sprite::get_offset);
ObjectTypeDB::bind_method(_MD("set_flip_h","flip_h"),&Sprite::set_flip_h);
ObjectTypeDB::bind_method(_MD("is_flipped_h"),&Sprite::is_flipped_h);
ObjectTypeDB::bind_method(_MD("set_flip_v","flip_v"),&Sprite::set_flip_v);
ObjectTypeDB::bind_method(_MD("is_flipped_v"),&Sprite::is_flipped_v);
ObjectTypeDB::bind_method(_MD("set_region","enabled"),&Sprite::set_region);
ObjectTypeDB::bind_method(_MD("is_region"),&Sprite::is_region);
ObjectTypeDB::bind_method(_MD("set_region_rect","rect"),&Sprite::set_region_rect);
ObjectTypeDB::bind_method(_MD("get_region_rect"),&Sprite::get_region_rect);
ObjectTypeDB::bind_method(_MD("set_frame","frame"),&Sprite::set_frame);
ObjectTypeDB::bind_method(_MD("get_frame"),&Sprite::get_frame);
ObjectTypeDB::bind_method(_MD("set_vframes","vframes"),&Sprite::set_vframes);
ObjectTypeDB::bind_method(_MD("get_vframes"),&Sprite::get_vframes);
ObjectTypeDB::bind_method(_MD("set_hframes","hframes"),&Sprite::set_hframes);
ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite::get_hframes);
ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&Sprite::set_modulate);
ObjectTypeDB::bind_method(_MD("get_modulate"),&Sprite::get_modulate);
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("texture_changed"));
ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture"));
ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h"));
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v"));
ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes"));
ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes"));
ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame"));
ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region"));
ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect"));
}
Sprite::Sprite() {
centered=true;
hflip=false;
vflip=false;
region=false;
frame=0;
vframes=1;
hframes=1;
modulate=Color(1,1,1,1);
}
//////////////////////////// VPSPRITE
///
///
///
void ViewportSprite::edit_set_pivot(const Point2& p_pivot) {
set_offset(p_pivot);
}
Point2 ViewportSprite::edit_get_pivot() const {
return get_offset();
}
bool ViewportSprite::edit_has_pivot() const {
return true;
}
void ViewportSprite::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_TREE: {
if (!viewport_path.is_empty()) {
Node *n = get_node(viewport_path);
ERR_FAIL_COND(!n);
Viewport *vp=n->cast_to<Viewport>();
ERR_FAIL_COND(!vp);
Ref<RenderTargetTexture> rtt = vp->get_render_target_texture();
texture=rtt;
texture->connect("changed",this,"update");
item_rect_changed();
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (texture.is_valid()) {
texture->disconnect("changed",this,"update");
texture=Ref<Texture>();
}
} break;
case NOTIFICATION_DRAW: {
if (texture.is_null())
return;
RID ci = get_canvas_item();
/*
texture->draw(ci,Point2());
break;
*/
Size2i s;
Rect2i src_rect;
s = texture->get_size();
src_rect.size=s;
Point2 ofs=offset;
if (centered)
ofs-=s/2;
if (OS::get_singleton()->get_use_pixel_snap()) {
ofs=ofs.floor();
}
Rect2 dst_rect(ofs,s);
texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
} break;
}
}
void ViewportSprite::set_viewport_path(const NodePath& p_viewport) {
viewport_path=p_viewport;
update();
if (!is_inside_tree())
return;
if (texture.is_valid()) {
texture->disconnect("changed",this,"update");
texture=Ref<Texture>();
}
if (viewport_path.is_empty())
return;
Node *n = get_node(viewport_path);
ERR_FAIL_COND(!n);
Viewport *vp=n->cast_to<Viewport>();
ERR_FAIL_COND(!vp);
Ref<RenderTargetTexture> rtt = vp->get_render_target_texture();
texture=rtt;
if (texture.is_valid()) {
texture->connect("changed",this,"update");
}
item_rect_changed();
}
NodePath ViewportSprite::get_viewport_path() const {
return viewport_path;
}
void ViewportSprite::set_centered(bool p_center) {
centered=p_center;
update();
item_rect_changed();
}
bool ViewportSprite::is_centered() const {
return centered;
}
void ViewportSprite::set_offset(const Point2& p_offset) {
offset=p_offset;
update();
item_rect_changed();
}
Point2 ViewportSprite::get_offset() const {
return offset;
}
void ViewportSprite::set_modulate(const Color& p_color) {
modulate=p_color;
update();
}
Color ViewportSprite::get_modulate() const{
return modulate;
}
Rect2 ViewportSprite::get_item_rect() const {
if (texture.is_null())
return Rect2(0,0,1,1);
//if (texture.is_null())
// return CanvasItem::get_item_rect();
Size2i s;
s = texture->get_size();
Point2 ofs=offset;
if (centered)
ofs-=s/2;
if (s==Size2(0,0))
s=Size2(1,1);
return Rect2(ofs,s);
}
String ViewportSprite::get_configuration_warning() const {
if (!has_node(viewport_path) || !get_node(viewport_path) || !get_node(viewport_path)->cast_to<Viewport>()) {
return TTR("Path property must point to a valid Viewport node to work. Such Viewport must be set to 'render target' mode.");
} else {
Node *n = get_node(viewport_path);
if (n) {
Viewport *vp = n->cast_to<Viewport>();
if (!vp->is_set_as_render_target()) {
return TTR("The Viewport set in the path property must be set as 'render target' in order for this sprite to work.");
}
}
}
return String();
}
void ViewportSprite::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_viewport_path","path"),&ViewportSprite::set_viewport_path);
ObjectTypeDB::bind_method(_MD("get_viewport_path"),&ViewportSprite::get_viewport_path);
ObjectTypeDB::bind_method(_MD("set_centered","centered"),&ViewportSprite::set_centered);
ObjectTypeDB::bind_method(_MD("is_centered"),&ViewportSprite::is_centered);
ObjectTypeDB::bind_method(_MD("set_offset","offset"),&ViewportSprite::set_offset);
ObjectTypeDB::bind_method(_MD("get_offset"),&ViewportSprite::get_offset);
ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&ViewportSprite::set_modulate);
ObjectTypeDB::bind_method(_MD("get_modulate"),&ViewportSprite::get_modulate);
ADD_PROPERTYNZ( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path"));
ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered"));
ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset"));
ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate"));
}
ViewportSprite::ViewportSprite() {
centered=true;
modulate=Color(1,1,1,1);
}