diff options
Diffstat (limited to 'scene/2d')
49 files changed, 10671 insertions, 0 deletions
diff --git a/scene/2d/SCsub b/scene/2d/SCsub new file mode 100644 index 0000000000..055d2f2474 --- /dev/null +++ b/scene/2d/SCsub @@ -0,0 +1,7 @@ +Import('env') + +env.add_source_files(env.scene_sources,"*.cpp") + +Export('env') + + diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp new file mode 100644 index 0000000000..316dffb3f9 --- /dev/null +++ b/scene/2d/animated_sprite.cpp @@ -0,0 +1,352 @@ +/*************************************************************************/ +/* animated_sprite.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "animated_sprite.h" + +void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) { + + set_offset(p_pivot); +} + +Point2 AnimatedSprite::edit_get_pivot() const { + + return get_offset(); +} +bool AnimatedSprite::edit_has_pivot() const { + + return true; +} + + +void SpriteFrames::add_frame(const Ref<Texture>& p_frame,int p_at_pos) { + + if (p_at_pos>=0 && p_at_pos<frames.size()) + frames.insert(p_at_pos,p_frame); + else + frames.push_back(p_frame); + + emit_changed(); +} + +int SpriteFrames::get_frame_count() const { + + return frames.size(); +} + +void SpriteFrames::remove_frame(int p_idx) { + + frames.remove(p_idx); + emit_changed(); +} +void SpriteFrames::clear() { + + frames.clear(); + emit_changed(); +} + + +Array SpriteFrames::_get_frames() const { + + Array arr; + arr.resize(frames.size()); + for(int i=0;i<frames.size();i++) + arr[i]=frames[i]; + + return arr; +} + +void SpriteFrames::_set_frames(const Array& p_frames) { + + frames.resize(p_frames.size()); + for(int i=0;i<frames.size();i++) + frames[i]=p_frames[i]; + +} + + +void SpriteFrames::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("add_frame","frame","atpos"),&SpriteFrames::add_frame,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("get_frame_count"),&SpriteFrames::get_frame_count); + ObjectTypeDB::bind_method(_MD("get_frame","idx"),&SpriteFrames::get_frame); + ObjectTypeDB::bind_method(_MD("set_frame","idx","txt"),&SpriteFrames::set_frame); + ObjectTypeDB::bind_method(_MD("remove_frame","idx"),&SpriteFrames::remove_frame); + ObjectTypeDB::bind_method(_MD("clear"),&SpriteFrames::clear); + + ObjectTypeDB::bind_method(_MD("_set_frames"),&SpriteFrames::_set_frames); + ObjectTypeDB::bind_method(_MD("_get_frames"),&SpriteFrames::_get_frames); + + ADD_PROPERTYNZ( PropertyInfo(Variant::ARRAY,"frames",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_frames"),_SCS("_get_frames")); + +} + + + + +SpriteFrames::SpriteFrames() { + + +} + + + + + + + +////////////////////////// + + +void AnimatedSprite::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_DRAW: { + + if (frames.is_null()) + return; + + if (frame<0 || frame>=frames->get_frame_count()) + return; + + Ref<Texture> texture = frames->get_frame(frame); + if (texture.is_null()) + return; + + //print_line("DECIDED TO DRAW"); + + RID ci = get_canvas_item(); + + /* + texture->draw(ci,Point2()); + break; + */ + + Size2i s; + s = texture->get_size(); + Point2i ofs=offset; + if (centered) + ofs-=s/2; + + Rect2i 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(ci,dst_rect,false,modulate); +// VisualServer::get_singleton()->canvas_item_add_texture_rect_region(ci,dst_rect,texture->get_rid(),src_rect,modulate); + + } break; + } + +} + +void AnimatedSprite::set_sprite_frames(const Ref<SpriteFrames> &p_frames) { + + if (frames.is_valid()) + frames->disconnect("changed",this,"_res_changed"); + frames=p_frames; + if (frames.is_valid()) + frames->connect("changed",this,"_res_changed"); + + if (!frames.is_valid()) { + frame=0; + + } else { + set_frame(frame); + } + update(); + +} + +Ref<SpriteFrames> AnimatedSprite::get_sprite_frames() const { + + return frames; +} + +void AnimatedSprite::set_frame(int p_frame) { + + if (!frames.is_valid()) { + return; + } + if (p_frame>=frames->get_frame_count()) + p_frame=frames->get_frame_count()-1; + if (p_frame<0) + p_frame=0; + + if (frame==p_frame) + return; + + frame=p_frame; + update(); + _change_notify("frame"); + + +} +int AnimatedSprite::get_frame() const { + + return frame; +} + + +void AnimatedSprite::set_centered(bool p_center) { + + centered=p_center; + update(); + item_rect_changed(); +} + +bool AnimatedSprite::is_centered() const { + + return centered; +} + +void AnimatedSprite::set_offset(const Point2& p_offset) { + + offset=p_offset; + update(); + item_rect_changed(); +} +Point2 AnimatedSprite::get_offset() const { + + return offset; +} + +void AnimatedSprite::set_flip_h(bool p_flip) { + + hflip=p_flip; + update(); +} +bool AnimatedSprite::is_flipped_h() const { + + return hflip; +} + +void AnimatedSprite::set_flip_v(bool p_flip) { + + vflip=p_flip; + update(); +} +bool AnimatedSprite::is_flipped_v() const { + + return vflip; +} + + +void AnimatedSprite::set_modulate(const Color& p_color) { + + modulate=p_color; + update(); +} + +Color AnimatedSprite::get_modulate() const{ + + return modulate; +} + + +Rect2 AnimatedSprite::get_item_rect() const { + + if (!frames.is_valid() || !frames->get_frame_count() || frame<0 || frame>=frames->get_frame_count()) { + return Node2D::get_item_rect(); + } + + Ref<Texture> t = frames->get_frame(frame); + if (t.is_null()) + return Node2D::get_item_rect(); + Size2i s = t->get_size(); + + Point2i ofs=offset; + if (centered) + ofs-=s/2; + + if (s==Size2(0,0)) + s=Size2(1,1); + + return Rect2(ofs,s); +} + +void AnimatedSprite::_res_changed() { + + set_frame(frame); + update(); +} + +void AnimatedSprite::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_sprite_frames","sprite_frames:SpriteFrames"),&AnimatedSprite::set_sprite_frames); + ObjectTypeDB::bind_method(_MD("get_sprite_frames:SpriteFrames"),&AnimatedSprite::get_sprite_frames); + + ObjectTypeDB::bind_method(_MD("set_centered","centered"),&AnimatedSprite::set_centered); + ObjectTypeDB::bind_method(_MD("is_centered"),&AnimatedSprite::is_centered); + + ObjectTypeDB::bind_method(_MD("set_offset","offset"),&AnimatedSprite::set_offset); + ObjectTypeDB::bind_method(_MD("get_offset"),&AnimatedSprite::get_offset); + + ObjectTypeDB::bind_method(_MD("set_flip_h","flip_h"),&AnimatedSprite::set_flip_h); + ObjectTypeDB::bind_method(_MD("is_flipped_h"),&AnimatedSprite::is_flipped_h); + + ObjectTypeDB::bind_method(_MD("set_flip_v","flip_v"),&AnimatedSprite::set_flip_v); + ObjectTypeDB::bind_method(_MD("is_flipped_v"),&AnimatedSprite::is_flipped_v); + + ObjectTypeDB::bind_method(_MD("set_frame","frame"),&AnimatedSprite::set_frame); + ObjectTypeDB::bind_method(_MD("get_frame"),&AnimatedSprite::get_frame); + + ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&AnimatedSprite::set_modulate); + ObjectTypeDB::bind_method(_MD("get_modulate"),&AnimatedSprite::get_modulate); + + + ObjectTypeDB::bind_method(_MD("_res_changed"),&AnimatedSprite::_res_changed); + + ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); + ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); + +} + +AnimatedSprite::AnimatedSprite() { + + centered=true; + hflip=false; + vflip=false; + + frame=0; + + + modulate=Color(1,1,1,1); + + +} + + diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h new file mode 100644 index 0000000000..78d738240f --- /dev/null +++ b/scene/2d/animated_sprite.h @@ -0,0 +1,119 @@ +/*************************************************************************/ +/* animated_sprite.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef ANIMATED_SPRITE_H +#define ANIMATED_SPRITE_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/texture.h" + + +class SpriteFrames : public Resource { + + OBJ_TYPE(SpriteFrames,Resource); + + Vector< Ref<Texture> > frames; + + Array _get_frames() const; + void _set_frames(const Array& p_frames); +protected: + + static void _bind_methods(); + +public: + + + void add_frame(const Ref<Texture>& p_frame,int p_at_pos=-1); + int get_frame_count() const; + _FORCE_INLINE_ Ref<Texture> get_frame(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,frames.size(),Ref<Texture>()); return frames[p_idx]; } + void set_frame(int p_idx,const Ref<Texture>& p_frame){ ERR_FAIL_INDEX(p_idx,frames.size()); frames[p_idx]=p_frame; } + void remove_frame(int p_idx); + void clear(); + + SpriteFrames(); + +}; + + + +class AnimatedSprite : public Node2D { + + OBJ_TYPE(AnimatedSprite,Node2D); + + Ref<SpriteFrames> frames; + int frame; + + bool centered; + Point2 offset; + + bool hflip; + bool vflip; + + Color modulate; + + void _res_changed(); +protected: + + static void _bind_methods(); + void _notification(int p_what); + +public: + + + virtual void edit_set_pivot(const Point2& p_pivot); + virtual Point2 edit_get_pivot() const; + virtual bool edit_has_pivot() const; + + void set_sprite_frames(const Ref<SpriteFrames> &p_frames); + Ref<SpriteFrames> get_sprite_frames() const; + + void set_frame(int p_frame); + int get_frame() const; + + void set_centered(bool p_center); + bool is_centered() const; + + void set_offset(const Point2& p_offset); + Point2 get_offset() const; + + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + + void set_modulate(const Color& p_color); + Color get_modulate() const; + + virtual Rect2 get_item_rect() const; + + + AnimatedSprite(); +}; + +#endif // ANIMATED_SPRITE_H diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp new file mode 100644 index 0000000000..70b5a652d5 --- /dev/null +++ b/scene/2d/area_2d.cpp @@ -0,0 +1,326 @@ +/*************************************************************************/ +/* area_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "area_2d.h" +#include "scene/scene_string_names.h" +#include "servers/physics_2d_server.h" +void Area2D::set_space_override_mode(SpaceOverride p_mode) { + + space_override=p_mode; + Physics2DServer::get_singleton()->area_set_space_override_mode(get_rid(),Physics2DServer::AreaSpaceOverrideMode(p_mode)); + + +} +Area2D::SpaceOverride Area2D::get_space_override_mode() const{ + + return space_override; +} + +void Area2D::set_gravity_is_point(bool p_enabled){ + + gravity_is_point=p_enabled; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY_IS_POINT,p_enabled); + +} +bool Area2D::is_gravity_a_point() const{ + + return gravity_is_point; +} + +void Area2D::set_gravity_vector(const Vector2& p_vec){ + + gravity_vec=p_vec; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,p_vec); + +} +Vector2 Area2D::get_gravity_vector() const{ + + return gravity_vec; +} + +void Area2D::set_gravity(real_t p_gravity){ + + gravity=p_gravity; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_GRAVITY,p_gravity); +} +real_t Area2D::get_gravity() const{ + + return gravity; +} + +void Area2D::set_density(real_t p_density){ + + density=p_density; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_DENSITY,p_density); +} +real_t Area2D::get_density() const{ + + return density; +} + +void Area2D::set_priority(real_t p_priority){ + + priority=p_priority; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_PRIORITY,p_priority); +} +real_t Area2D::get_priority() const{ + + return priority; +} + + +void Area2D::_body_enter_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + + Map<ObjectID,BodyState>::Element *E=body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->get().in_scene); + + E->get().in_scene=true; + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } + +} + +void Area2D::_body_exit_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + Map<ObjectID,BodyState>::Element *E=body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->get().in_scene); + E->get().in_scene=false; + emit_signal(SceneStringNames::get_singleton()->body_exit,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } + +} + +void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape) { + + bool body_in = p_status==Physics2DServer::AREA_BODY_ADDED; + ObjectID objid=p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = obj ? obj->cast_to<Node>() : NULL; + + Map<ObjectID,BodyState>::Element *E=body_map.find(objid); + + ERR_FAIL_COND(!body_in && !E); + + if (body_in) { + if (!E) { + + E = body_map.insert(objid,BodyState()); + E->get().rc=0; + E->get().in_scene=node && node->is_inside_scene(); + if (node) { + node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + } + } + + } + E->get().rc++; + if (node) + E->get().shapes.insert(ShapePair(p_body_shape,p_area_shape)); + + + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_area_shape); + } + + } else { + + E->get().rc--; + + if (node) + E->get().shapes.erase(ShapePair(p_body_shape,p_area_shape)); + + bool eraseit=false; + + if (E->get().rc==0) { + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); + node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + if (E->get().in_scene) + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + } + + eraseit=true; + + } + if (node && E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_area_shape); + } + + if (eraseit) + body_map.erase(E); + + } + +} + + +void Area2D::_clear_monitoring() { + + + Map<ObjectID,BodyState> bmcopy = body_map; + body_map.clear(); + //disconnect all monitored stuff + + for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) { + + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_CONTINUE(!node); + if (!E->get().in_scene) + continue; + + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } + + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); + node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + } + +} + +void Area2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_EXIT_SCENE: { + + _clear_monitoring(); + } break; + } + +} + + +void Area2D::set_enable_monitoring(bool p_enable) { + + if (p_enable==monitoring) + return; + + monitoring=p_enable; + + if (monitoring) { + + Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout"); + } else { + Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName()); + _clear_monitoring(); + + } +} + +bool Area2D::is_monitoring_enabled() const { + + return monitoring; +} + + +void Area2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area2D::_body_enter_scene); + ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area2D::_body_exit_scene); + + ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area2D::set_space_override_mode); + ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area2D::get_space_override_mode); + + ObjectTypeDB::bind_method(_MD("set_gravity_is_point","enable"),&Area2D::set_gravity_is_point); + ObjectTypeDB::bind_method(_MD("is_gravity_a_point"),&Area2D::is_gravity_a_point); + + ObjectTypeDB::bind_method(_MD("set_gravity_vector","vector"),&Area2D::set_gravity_vector); + ObjectTypeDB::bind_method(_MD("get_gravity_vector"),&Area2D::get_gravity_vector); + + ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area2D::set_gravity); + ObjectTypeDB::bind_method(_MD("get_gravity"),&Area2D::get_gravity); + + ObjectTypeDB::bind_method(_MD("set_density","density"),&Area2D::set_density); + ObjectTypeDB::bind_method(_MD("get_density"),&Area2D::get_density); + + ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority); + ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority); + + ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring); + ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled); + + ObjectTypeDB::bind_method(_MD("_body_inout"),&Area2D::_body_inout); + + + ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body"))); + ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body"))); + + ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density")); + ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); + +} + +Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_create(),true) { + + space_override=SPACE_OVERRIDE_DISABLED; + set_gravity(98);; + set_gravity_vector(Vector2(0,1)); + gravity_is_point=false; + density=0.1; + priority=0; + monitoring=false; + +} + +Area2D::~Area2D() { + + +} diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h new file mode 100644 index 0000000000..b4c8edf138 --- /dev/null +++ b/scene/2d/area_2d.h @@ -0,0 +1,122 @@ +/*************************************************************************/ +/* area_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef AREA_2D_H +#define AREA_2D_H + +#include "scene/2d/collision_object_2d.h" +#include "vset.h" + +class Area2D : public CollisionObject2D { + + OBJ_TYPE( Area2D, CollisionObject2D ); +public: + + enum SpaceOverride { + SPACE_OVERRIDE_DISABLED, + SPACE_OVERRIDE_COMBINE, + SPACE_OVERRIDE_REPLACE + }; +private: + + + SpaceOverride space_override; + Vector2 gravity_vec; + real_t gravity; + bool gravity_is_point; + real_t density; + int priority; + bool monitoring; + + void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape); + + void _body_enter_scene(ObjectID p_id); + void _body_exit_scene(ObjectID p_id); + + struct ShapePair { + + int body_shape; + int area_shape; + bool operator<(const ShapePair& p_sp) const { + if (body_shape==p_sp.body_shape) + return area_shape < p_sp.area_shape; + else + return body_shape < p_sp.body_shape; + } + + ShapePair() {} + ShapePair(int p_bs, int p_as) { body_shape=p_bs; area_shape=p_as; } + }; + + struct BodyState { + + int rc; + bool in_scene; + VSet<ShapePair> shapes; + }; + + Map<ObjectID,BodyState> body_map; + + void _clear_monitoring(); + + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_space_override_mode(SpaceOverride p_mode); + SpaceOverride get_space_override_mode() const; + + void set_gravity_is_point(bool p_enabled); + bool is_gravity_a_point() const; + + void set_gravity_vector(const Vector2& p_vec); + Vector2 get_gravity_vector() const; + + void set_gravity(real_t p_gravity); + real_t get_gravity() const; + + void set_density(real_t p_density); + real_t get_density() const; + + void set_priority(real_t p_priority); + real_t get_priority() const; + + void set_enable_monitoring(bool p_enable); + bool is_monitoring_enabled() const; + + + Area2D(); + ~Area2D(); +}; + +VARIANT_ENUM_CAST(Area2D::SpaceOverride); + +#endif // AREA_2D_H diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp new file mode 100644 index 0000000000..1920ce0081 --- /dev/null +++ b/scene/2d/camera_2d.cpp @@ -0,0 +1,484 @@ +/*************************************************************************/ +/* camera_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "camera_2d.h"
+#include "scene/scene_string_names.h"
+#include "servers/visual_server.h"
+
+void Camera2D::_update_scroll() {
+
+
+ if (!is_inside_scene())
+ return;
+
+ if (get_scene()->is_editor_hint()) {
+ update(); //will just be drawn
+ return;
+ }
+
+ if (current) {
+ Matrix32 xform = get_camera_transform();
+
+ RID vp = viewport->get_viewport();
+ if (viewport) {
+ viewport->set_canvas_transform( xform );
+ }
+ get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_camera_moved",xform);
+ };
+
+}
+
+void Camera2D::set_zoom(const Vector2 &p_zoom) {
+
+ zoom = p_zoom;
+ _update_scroll();
+};
+
+Vector2 Camera2D::get_zoom() const {
+
+ return zoom;
+};
+
+
+Matrix32 Camera2D::get_camera_transform() {
+
+ if (!get_scene())
+ return Matrix32();
+
+ Size2 screen_size = get_viewport_rect().size;
+ screen_size=get_viewport_rect().size;
+
+
+ Point2 new_camera_pos = get_global_transform().get_origin();
+ Point2 ret_camera_pos;
+
+ if (!first) {
+
+
+ if (centered) {
+
+ if (h_drag_enabled) {
+ camera_pos.x = MIN( camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
+ camera_pos.x = MAX( camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
+ } else {
+
+ if (h_ofs<0) {
+ camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs;
+ } else {
+ camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs;
+ }
+ }
+
+ if (v_drag_enabled) {
+
+ camera_pos.y = MIN( camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
+ camera_pos.y = MAX( camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));
+
+ } else {
+
+ if (v_ofs<0) {
+ camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs;
+ } else {
+ camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs;
+ }
+ }
+
+ }
+
+
+ if (smoothing>0.0) {
+
+ float c = smoothing*get_fixed_process_delta_time();
+ smoothed_camera_pos = ((new_camera_pos-smoothed_camera_pos)*c)+smoothed_camera_pos;
+ ret_camera_pos=smoothed_camera_pos;
+// camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
+ } else {
+
+ ret_camera_pos=smoothed_camera_pos=camera_pos;
+
+ }
+
+
+
+ } else {
+ ret_camera_pos=smoothed_camera_pos=camera_pos=new_camera_pos;
+ first=false;
+ }
+
+
+ Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2());;
+ screen_offset+=offset;
+
+ Rect2 screen_rect(-screen_offset+ret_camera_pos,screen_size);
+ if (screen_rect.pos.x + screen_rect.size.x > limit[MARGIN_RIGHT])
+ screen_rect.pos.x = limit[MARGIN_RIGHT] - screen_rect.size.x;
+
+ if (screen_rect.pos.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
+ screen_rect.pos.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;
+
+
+ if (screen_rect.pos.x < limit[MARGIN_LEFT])
+ screen_rect.pos.x=limit[MARGIN_LEFT];
+
+ if (screen_rect.pos.y < limit[MARGIN_TOP])
+ screen_rect.pos.y =limit[MARGIN_TOP];
+
+ camera_screen_center=screen_rect.pos+screen_rect.size*0.5;
+
+ Matrix32 xform;
+ xform.scale_basis(zoom);
+ xform.set_origin(screen_rect.pos/*.floor()*/);
+
+
+/*
+ if (0) {
+
+ xform = get_global_transform() * xform;
+ } else {
+
+ xform.elements[2]+=get_global_transform().get_origin();
+ }
+*/
+
+
+ return (xform).affine_inverse();
+}
+
+
+
+void Camera2D::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_FIXED_PROCESS: {
+
+ _update_scroll();
+
+ } break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+
+ if (!is_fixed_processing())
+ _update_scroll();
+
+ } break;
+ case NOTIFICATION_ENTER_SCENE: {
+
+ viewport = NULL;
+ Node *n=this;
+ while(n){
+
+ viewport = n->cast_to<Viewport>();
+ if (viewport)
+ break;
+ n=n->get_parent();
+ }
+
+ canvas = get_canvas();
+
+ RID vp = viewport->get_viewport();
+
+ group_name = "__cameras_"+itos(vp.get_id());
+ canvas_group_name ="__cameras_c"+itos(canvas.get_id());
+ add_to_group(group_name);
+ add_to_group(canvas_group_name);
+
+ _update_scroll();
+ first=true;
+
+
+ } break;
+ case NOTIFICATION_EXIT_SCENE: {
+
+ if (is_current()) {
+ if (viewport) {
+ viewport->set_canvas_transform( Matrix32() );
+ }
+ }
+ remove_from_group(group_name);
+ remove_from_group(canvas_group_name);
+ viewport=NULL;
+
+ } break;
+ }
+}
+
+void Camera2D::set_offset(const Vector2& p_offset) {
+
+ offset=p_offset;
+ _update_scroll();
+
+}
+
+Vector2 Camera2D::get_offset() const{
+
+ return offset;
+}
+
+void Camera2D::set_centered(bool p_centered){
+
+ centered=p_centered;
+ _update_scroll();
+}
+
+bool Camera2D::is_centered() const {
+
+ return centered;
+}
+
+
+void Camera2D::_make_current(Object *p_which) {
+
+ if (p_which==this) {
+
+ current=true;
+ _update_scroll();
+ } else {
+ current=false;
+ }
+}
+
+
+void Camera2D::_set_current(bool p_current) {
+
+ if (p_current)
+ make_current();
+
+ current=p_current;
+}
+
+bool Camera2D::is_current() const {
+
+ return current;
+}
+
+void Camera2D::make_current() {
+
+ if (!is_inside_scene()) {
+ current=true;
+ } else {
+ get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_make_current",this);
+ }
+}
+
+void Camera2D::set_limit(Margin p_margin,int p_limit) {
+
+ ERR_FAIL_INDEX(p_margin,4);
+ limit[p_margin]=p_limit;
+}
+
+int Camera2D::get_limit(Margin p_margin) const{
+
+ ERR_FAIL_INDEX_V(p_margin,4,0);
+ return limit[p_margin];
+
+}
+
+void Camera2D::set_drag_margin(Margin p_margin,float p_drag_margin) {
+
+ ERR_FAIL_INDEX(p_margin,4);
+ drag_margin[p_margin]=p_drag_margin;
+}
+
+float Camera2D::get_drag_margin(Margin p_margin) const{
+
+ ERR_FAIL_INDEX_V(p_margin,4,0);
+ return drag_margin[p_margin];
+
+}
+
+
+Vector2 Camera2D::get_camera_pos() const {
+
+
+ return camera_pos;
+}
+
+void Camera2D::force_update_scroll() {
+
+
+ _update_scroll();
+}
+
+
+void Camera2D::set_follow_smoothing(float p_speed) {
+
+ smoothing=p_speed;
+ if (smoothing>0)
+ set_fixed_process(true);
+ else
+ set_fixed_process(false);
+}
+
+float Camera2D::get_follow_smoothing() const{
+
+ return smoothing;
+}
+
+Point2 Camera2D::get_camera_screen_center() const {
+
+ return camera_screen_center;
+}
+
+
+void Camera2D::set_h_drag_enabled(bool p_enabled) {
+
+ h_drag_enabled=p_enabled;
+}
+
+bool Camera2D::is_h_drag_enabled() const{
+
+ return h_drag_enabled;
+}
+
+void Camera2D::set_v_drag_enabled(bool p_enabled){
+
+ v_drag_enabled=p_enabled;
+}
+
+bool Camera2D::is_v_drag_enabled() const{
+
+ return v_drag_enabled;
+}
+
+void Camera2D::set_v_offset(float p_offset) {
+
+ v_ofs=p_offset;
+}
+
+float Camera2D::get_v_offset() const{
+
+ return v_ofs;
+}
+
+void Camera2D::set_h_offset(float p_offset){
+
+ h_ofs=p_offset;
+}
+float Camera2D::get_h_offset() const{
+
+ return h_ofs;
+}
+
+
+void Camera2D::_bind_methods() {
+
+ ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Camera2D::set_offset);
+ ObjectTypeDB::bind_method(_MD("get_offset"),&Camera2D::get_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Camera2D::set_centered);
+ ObjectTypeDB::bind_method(_MD("is_centered"),&Camera2D::is_centered);
+
+ ObjectTypeDB::bind_method(_MD("make_current"),&Camera2D::make_current);
+ ObjectTypeDB::bind_method(_MD("_make_current"),&Camera2D::_make_current);
+
+ ObjectTypeDB::bind_method(_MD("_update_scroll"),&Camera2D::_update_scroll);
+
+
+ ObjectTypeDB::bind_method(_MD("_set_current","current"),&Camera2D::_set_current);
+ ObjectTypeDB::bind_method(_MD("is_current"),&Camera2D::is_current);
+
+ ObjectTypeDB::bind_method(_MD("set_limit","margin","limit"),&Camera2D::set_limit);
+ ObjectTypeDB::bind_method(_MD("get_limit","margin"),&Camera2D::get_limit);
+
+ ObjectTypeDB::bind_method(_MD("set_v_drag_enabled","enabled"),&Camera2D::set_v_drag_enabled);
+ ObjectTypeDB::bind_method(_MD("is_v_drag_enabled"),&Camera2D::is_v_drag_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_h_drag_enabled","enabled"),&Camera2D::set_h_drag_enabled);
+ ObjectTypeDB::bind_method(_MD("is_h_drag_enabled"),&Camera2D::is_h_drag_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_v_offset","ofs"),&Camera2D::set_v_offset);
+ ObjectTypeDB::bind_method(_MD("get_v_offset"),&Camera2D::get_v_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_h_offset","ofs"),&Camera2D::set_h_offset);
+ ObjectTypeDB::bind_method(_MD("get_h_offset"),&Camera2D::get_h_offset);
+
+ ObjectTypeDB::bind_method(_MD("set_drag_margin","margin","drag_margin"),&Camera2D::set_drag_margin);
+ ObjectTypeDB::bind_method(_MD("get_drag_margin","margin"),&Camera2D::get_drag_margin);
+
+ ObjectTypeDB::bind_method(_MD("get_camera_pos"),&Camera2D::get_camera_pos);
+ ObjectTypeDB::bind_method(_MD("get_camera_screen_center"),&Camera2D::get_camera_screen_center);
+
+ ObjectTypeDB::bind_method(_MD("set_zoom"),&Camera2D::set_zoom);
+ ObjectTypeDB::bind_method(_MD("get_zoom"),&Camera2D::get_zoom);
+
+
+ ObjectTypeDB::bind_method(_MD("set_follow_smoothing","follow_smoothing"),&Camera2D::set_follow_smoothing);
+ ObjectTypeDB::bind_method(_MD("get_follow_smoothing"),&Camera2D::get_follow_smoothing);
+
+ ObjectTypeDB::bind_method(_MD("force_update_scroll"),&Camera2D::force_update_scroll);
+
+
+ ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"centered"),_SCS("set_centered"),_SCS("is_centered"));
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"current"),_SCS("_set_current"),_SCS("is_current"));
+ ADD_PROPERTY( PropertyInfo(Variant::REAL,"smoothing"),_SCS("set_follow_smoothing"),_SCS("get_follow_smoothing") );
+ ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"zoom"),_SCS("set_zoom"),_SCS("get_zoom") );
+
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/left"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_LEFT);
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/top"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_TOP);
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/right"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_RIGHT);
+ ADD_PROPERTYI( PropertyInfo(Variant::INT,"limit/bottom"),_SCS("set_limit"),_SCS("get_limit"),MARGIN_BOTTOM);
+
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"drag_margin/h_enabled"),_SCS("set_h_drag_enabled"),_SCS("is_h_drag_enabled") );
+ ADD_PROPERTY( PropertyInfo(Variant::BOOL,"drag_margin/v_enabled"),_SCS("set_v_drag_enabled"),_SCS("is_v_drag_enabled") );
+
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/left",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_LEFT);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/top",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_TOP);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/right",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_RIGHT);
+ ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/bottom",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_BOTTOM);
+
+
+
+}
+
+Camera2D::Camera2D() {
+
+
+
+ centered=true;
+ current=false;
+ limit[MARGIN_LEFT]=-10000000;
+ limit[MARGIN_TOP]=-10000000;
+ limit[MARGIN_RIGHT]=10000000;
+ limit[MARGIN_BOTTOM]=10000000;
+ drag_margin[MARGIN_LEFT]=0.2;
+ drag_margin[MARGIN_TOP]=0.2;
+ drag_margin[MARGIN_RIGHT]=0.2;
+ drag_margin[MARGIN_BOTTOM]=0.2;
+ camera_pos=Vector2();
+
+ smoothing=0.0;
+ zoom = Vector2(1, 1);
+
+ h_drag_enabled=true;
+ v_drag_enabled=true;
+ h_ofs=0;
+ v_ofs=0;
+
+}
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h new file mode 100644 index 0000000000..9d06df2d1b --- /dev/null +++ b/scene/2d/camera_2d.h @@ -0,0 +1,118 @@ +/*************************************************************************/ +/* camera_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef CAMERA_2D_H
+#define CAMERA_2D_H
+
+#include "scene/2d/node_2d.h"
+#include "scene/main/viewport.h"
+
+
+class Camera2D : public Node2D {
+
+ OBJ_TYPE( Camera2D, Node2D );
+
+protected:
+ Point2 camera_pos;
+ Point2 smoothed_camera_pos;
+ bool first;
+
+ Viewport *viewport;
+
+ StringName group_name;
+ StringName canvas_group_name;
+ RID canvas;
+ Vector2 offset;
+ Vector2 zoom;
+ bool centered;
+ bool current;
+ float smoothing;
+ int limit[4];
+ float drag_margin[4];
+
+ bool h_drag_enabled;
+ bool v_drag_enabled;
+ float h_ofs;
+ float v_ofs;
+
+
+ Point2 camera_screen_center;
+ void _update_scroll();
+
+ void _make_current(Object *p_which);
+ void _set_current(bool p_current);
+protected:
+
+ virtual Matrix32 get_camera_transform();
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_offset(const Vector2& p_offset);
+ Vector2 get_offset() const;
+
+ void set_centered(bool p_centered);
+ bool is_centered() const;
+
+ void set_limit(Margin p_margin,int p_limit);
+ int get_limit(Margin p_margin) const;
+
+
+ void set_h_drag_enabled(bool p_enabled);
+ bool is_h_drag_enabled() const;
+
+ void set_v_drag_enabled(bool p_enabled);
+ bool is_v_drag_enabled() const;
+
+ void set_drag_margin(Margin p_margin,float p_drag_margin);
+ float get_drag_margin(Margin p_margin) const;
+
+ void set_v_offset(float p_offset);
+ float get_v_offset() const;
+
+ void set_h_offset(float p_offset);
+ float get_h_offset() const;
+
+ void set_follow_smoothing(float p_speed);
+ float get_follow_smoothing() const;
+
+ void make_current();
+ bool is_current() const;
+
+ void set_zoom(const Vector2& p_zoom);
+ Vector2 get_zoom() const;
+
+ Point2 get_camera_screen_center() const;
+
+ Vector2 get_camera_pos() const;
+ void force_update_scroll();
+
+ Camera2D();
+};
+
+#endif // CAMERA_2D_H
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp new file mode 100644 index 0000000000..8a461c76fc --- /dev/null +++ b/scene/2d/canvas_item.cpp @@ -0,0 +1,875 @@ +/*************************************************************************/ +/* canvas_item.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "canvas_item.h" +#include "servers/visual_server.h" +#include "scene/main/viewport.h" +#include "scene/main/canvas_layer.h" +#include "message_queue.h" +#include "scene/scene_string_names.h" +#include "scene/resources/font.h" +#include "scene/resources/texture.h" +#include "scene/resources/style_box.h" + +bool CanvasItem::is_visible() const { + + if (!is_inside_scene()) + return false; + + const CanvasItem *p=this; + + while(p) { + if (p->hidden) + return false; + p=p->get_parent_item(); + } + + + return true; +} + +bool CanvasItem::is_hidden() const { + + /*if (!is_inside_scene()) + return false;*/ + + return hidden; +} + +void CanvasItem::_propagate_visibility_changed(bool p_visible) { + + notification(NOTIFICATION_VISIBILITY_CHANGED); + + if (p_visible) + update(); //todo optimize + else + emit_signal(SceneStringNames::get_singleton()->hide); + _block(); + + for(int i=0;i<get_child_count();i++) { + + CanvasItem *c=get_child(i)->cast_to<CanvasItem>(); + + if (c && c->hidden!=p_visible) //should the toplevels stop propagation? i think so but.. + c->_propagate_visibility_changed(p_visible); + } + + _unblock(); + +} + +void CanvasItem::show() { + + if (!hidden) + return; + + + hidden=false; + VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,true); + + if (!is_inside_scene()) + return; + + if (is_visible()) { + _propagate_visibility_changed(true); + } +} + + +void CanvasItem::hide() { + + if (hidden) + return; + + bool propagate=is_inside_scene() && is_visible(); + hidden=true; + VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false); + + if (!is_inside_scene()) + return; + if (propagate) + _propagate_visibility_changed(false); + +} + + +Variant CanvasItem::edit_get_state() const { + + + return Variant(); +} +void CanvasItem::edit_set_state(const Variant& p_state) { + + +} + +void CanvasItem::edit_set_rect(const Rect2& p_edit_rect) { + + //used by editors, implement at will +} + +void CanvasItem::edit_rotate(float p_rot) { + + +} + +Size2 CanvasItem::edit_get_minimum_size() const { + + return Size2(-1,-1); //no limit +} + +void CanvasItem::_update_callback() { + + + + if (!is_inside_scene()) { + pending_update=false; + return; + } + + + VisualServer::get_singleton()->canvas_item_clear(get_canvas_item()); + //todo updating = true - only allow drawing here + if (is_visible()) { //todo optimize this!! + if (first_draw) { + notification(NOTIFICATION_VISIBILITY_CHANGED); + first_draw=false; + } + drawing=true; + notification(NOTIFICATION_DRAW); + emit_signal(SceneStringNames::get_singleton()->draw); + if (get_script_instance()) { + Variant::CallError err; + get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_draw,NULL,0); + } + drawing=false; + + } + //todo updating = false + pending_update=false; // don't change to false until finished drawing (avoid recursive update) +} + +Matrix32 CanvasItem::get_global_transform_with_canvas() const { + + const CanvasItem *ci = this; + Matrix32 xform; + const CanvasItem *last_valid=NULL; + + while(ci) { + + last_valid=ci; + xform = ci->get_transform() * xform; + ci=ci->get_parent_item(); + } + + if (last_valid->canvas_layer) + return last_valid->canvas_layer->get_transform() * xform; + else + return xform; +} + +Matrix32 CanvasItem::get_global_transform() const { + + + if (global_invalid) { + + const CanvasItem *pi = get_parent_item(); + if (pi) + global_transform = pi->get_global_transform() * get_transform(); + else + global_transform = get_transform(); + + global_invalid=false; + } + + return global_transform; + +} + + +void CanvasItem::_queue_sort_children() { + + if (pending_children_sort) + return; + + pending_children_sort=true; + MessageQueue::get_singleton()->push_call(this,"_sort_children"); +} + +void CanvasItem::_sort_children() { + + pending_children_sort=false; + + if (!is_inside_scene()) + return; + + for(int i=0;i<get_child_count();i++) { + + Node *n = get_child(i); + CanvasItem *ci=n->cast_to<CanvasItem>(); + + if (ci) { + if (ci->toplevel || ci->group!="") + continue; + VisualServer::get_singleton()->canvas_item_raise(n->cast_to<CanvasItem>()->canvas_item); + } + } +} + +void CanvasItem::_raise_self() { + + if (!is_inside_scene()) + return; + + VisualServer::get_singleton()->canvas_item_raise(canvas_item); +} + + +void CanvasItem::_enter_canvas() { + + if ((!get_parent() || !get_parent()->cast_to<CanvasItem>()) || toplevel) { + + Node *n = this; + viewport=NULL; + canvas_layer=NULL; + + while(n) { + + if (n->cast_to<Viewport>()) { + + viewport = n->cast_to<Viewport>(); + break; + } + if (!canvas_layer && n->cast_to<CanvasLayer>()) { + + canvas_layer = n->cast_to<CanvasLayer>(); + } + n=n->get_parent(); + } + + RID canvas; + if (canvas_layer) + canvas=canvas_layer->get_world_2d()->get_canvas(); + else + canvas=viewport->find_world_2d()->get_canvas(); + + VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,canvas); + + group = "root_canvas"+itos(canvas.get_id()); + + add_to_group(group); + get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self"); + + } else { + + CanvasItem *parent = get_parent_item(); + viewport=parent->viewport; + VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,parent->get_canvas_item()); + parent->_queue_sort_children(); + } + + if (!viewport) { + + print_line("no viewport wtf!"); + } + pending_update=false; + update(); + + notification(NOTIFICATION_ENTER_CANVAS); + +} + +void CanvasItem::_exit_canvas() { + + notification(NOTIFICATION_EXIT_CANVAS,true); //reverse the notification + VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,RID()); + viewport=NULL; + canvas_layer=NULL; + group=""; + +} + + +void CanvasItem::_notification(int p_what) { + + + switch(p_what) { + case NOTIFICATION_ENTER_SCENE: { + + first_draw=true; + pending_children_sort=false; + if (get_parent()) { + CanvasItem *ci = get_parent()->cast_to<CanvasItem>(); + if (ci) + C=ci->children_items.push_back(this); + } + _enter_canvas(); + if (!block_transform_notify && !xform_change.in_list()) { + get_scene()->xform_change_list.add(&xform_change); + } + } break; + case NOTIFICATION_MOVED_IN_PARENT: { + + + if (group!="") { + get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self"); + } else { + CanvasItem *p = get_parent_item(); + ERR_FAIL_COND(!p); + p->_queue_sort_children(); + } + + + } break; + case NOTIFICATION_EXIT_SCENE: { + if (xform_change.in_list()) + get_scene()->xform_change_list.remove(&xform_change); + _exit_canvas(); + if (C) + get_parent()->cast_to<CanvasItem>()->children_items.erase(C); + } break; + case NOTIFICATION_DRAW: { + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + + } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + + emit_signal(SceneStringNames::get_singleton()->visibility_changed); + } break; + + } +} + +void CanvasItem::_set_visible_(bool p_visible) { + + if (p_visible) + show(); + else + hide(); +} +bool CanvasItem::_is_visible_() const { + + return !is_hidden(); +} + + +void CanvasItem::update() { + + if (!is_inside_scene()) + return; + if (pending_update) + return; + + pending_update=true; + + MessageQueue::get_singleton()->push_call(this,"_update_callback"); +} + +void CanvasItem::set_opacity(float p_opacity) { + + opacity=p_opacity; + VisualServer::get_singleton()->canvas_item_set_opacity(canvas_item,opacity); + +} +float CanvasItem::get_opacity() const { + + return opacity; +} + + +void CanvasItem::set_as_toplevel(bool p_toplevel) { + + if (toplevel==p_toplevel) + return; + + if (!is_inside_scene()) { + toplevel=p_toplevel; + return; + } + + _exit_canvas(); + toplevel=p_toplevel; + _enter_canvas(); +} + +bool CanvasItem::is_set_as_toplevel() const { + + return toplevel; +} + +CanvasItem *CanvasItem::get_parent_item() const { + + if (toplevel) + return NULL; + + Node *parent = get_parent(); + if (!parent) + return NULL; + + return parent->cast_to<CanvasItem>(); +} + + +void CanvasItem::set_self_opacity(float p_self_opacity) { + + self_opacity=p_self_opacity; + VisualServer::get_singleton()->canvas_item_set_self_opacity(canvas_item,self_opacity); + +} +float CanvasItem::get_self_opacity() const { + + return self_opacity; +} + +void CanvasItem::set_blend_mode(BlendMode p_blend_mode) { + + ERR_FAIL_INDEX(p_blend_mode,4); + blend_mode=p_blend_mode; + VisualServer::get_singleton()->canvas_item_set_blend_mode(canvas_item,VS::MaterialBlendMode(blend_mode)); + +} + +CanvasItem::BlendMode CanvasItem::get_blend_mode() const { + + return blend_mode; +} + + + +void CanvasItem::item_rect_changed() { + + update(); + emit_signal(SceneStringNames::get_singleton()->item_rect_changed); +} + + +void CanvasItem::draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + VisualServer::get_singleton()->canvas_item_add_line(canvas_item,p_from,p_to,p_color,p_width); +} + +void CanvasItem::draw_rect(const Rect2& p_rect, const Color& p_color) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + VisualServer::get_singleton()->canvas_item_add_rect(canvas_item,p_rect,p_color); + +} + +void CanvasItem::draw_circle(const Point2& p_pos, float p_radius, const Color& p_color) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + VisualServer::get_singleton()->canvas_item_add_circle(canvas_item,p_pos,p_radius,p_color); + +} + +void CanvasItem::draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + ERR_FAIL_COND(p_texture.is_null()); + + p_texture->draw(canvas_item,p_pos); +} + +void CanvasItem::draw_texture_rect(const Ref<Texture>& p_texture,const Rect2& p_rect, bool p_tile,const Color& p_modulate) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + ERR_FAIL_COND(p_texture.is_null()); + p_texture->draw_rect(canvas_item,p_rect,p_tile,p_modulate); + +} +void CanvasItem::draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + ERR_FAIL_COND(p_texture.is_null()); + p_texture->draw_rect_region(canvas_item,p_rect,p_src_rect,p_modulate); +} + +void CanvasItem::draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect) { + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + ERR_FAIL_COND(p_style_box.is_null()); + + p_style_box->draw(canvas_item,p_rect); + +} +void CanvasItem::draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture,float p_width) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + + VisualServer::get_singleton()->canvas_item_add_primitive(canvas_item,p_points,p_colors,p_uvs,rid,p_width); +} +void CanvasItem::draw_set_transform(const Point2& p_offset, float p_rot, const Size2& p_scale) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + Matrix32 xform(p_rot,p_offset); + xform.scale_basis(p_scale); + VisualServer::get_singleton()->canvas_item_set_transform(canvas_item,xform); +} + +void CanvasItem::draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + + VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item,p_points,p_colors,p_uvs,rid); + + +} + +void CanvasItem::draw_colored_polygon(const Vector<Point2>& p_points, const Color& p_color,const Vector<Point2>& p_uvs, Ref<Texture> p_texture) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + Vector<Color> colors; + colors.push_back(p_color); + RID rid = p_texture.is_valid() ? p_texture->get_rid() : RID(); + + VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item,p_points,colors,p_uvs,rid); +} + +void CanvasItem::draw_string(const Ref<Font>& p_font,const Point2& p_pos, const String& p_text,const Color& p_modulate,int p_clip_w) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL(); + } + + ERR_FAIL_COND(p_font.is_null()); + p_font->draw(canvas_item,p_pos,p_text,p_modulate,p_clip_w); + +} + +float CanvasItem::draw_char(const Ref<Font>& p_font,const Point2& p_pos, const String& p_char,const String& p_next,const Color& p_modulate) { + + if (!drawing) { + ERR_EXPLAIN("Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); + ERR_FAIL_V(0); + } + + ERR_FAIL_COND_V(p_char.length()!=1,0); + ERR_FAIL_COND_V(p_font.is_null(),0); + + return p_font->draw_char(canvas_item,p_pos,p_char[0],p_next.c_str()[0],p_modulate); + +} + + +void CanvasItem::_notify_transform(CanvasItem *p_node) { + + if (p_node->xform_change.in_list() && p_node->global_invalid) + return; //nothing to do + + p_node->global_invalid=true; + + if (!p_node->xform_change.in_list()) { + if (!p_node->block_transform_notify) { + if (p_node->is_inside_scene()) + get_scene()->xform_change_list.add(&p_node->xform_change); + } + } + + + for(List<CanvasItem*>::Element *E=p_node->children_items.front();E;E=E->next()) { + + CanvasItem* ci=E->get(); + if (ci->toplevel) + continue; + _notify_transform(ci); + } +} + + +Rect2 CanvasItem::get_viewport_rect() const { + + ERR_FAIL_COND_V(!is_inside_scene(),Rect2()); + return viewport->get_visible_rect(); +} + +RID CanvasItem::get_canvas() const { + + ERR_FAIL_COND_V(!is_inside_scene(),RID()); + + if (canvas_layer) + return canvas_layer->get_world_2d()->get_canvas(); + else + return viewport->find_world_2d()->get_canvas(); + + +} + +CanvasItem *CanvasItem::get_toplevel() const { + + CanvasItem *ci=const_cast<CanvasItem*>(this); + while(!ci->toplevel && ci->get_parent() && ci->get_parent()->cast_to<CanvasItem>()) { + ci=ci->get_parent()->cast_to<CanvasItem>(); + } + + return ci; +} + +Viewport *CanvasItem::get_viewport() const { + + return viewport; +} + + +Ref<World2D> CanvasItem::get_world_2d() const { + + ERR_FAIL_COND_V(!is_inside_scene(),Ref<World2D>()); + + CanvasItem *tl=get_toplevel(); + + if (tl->canvas_layer) { + return tl->canvas_layer->get_world_2d(); + } else if (tl->viewport) { + return tl->viewport->find_world_2d(); + } else { + return Ref<World2D>(); + } + +} + +RID CanvasItem::get_viewport_rid() const { + + ERR_FAIL_COND_V(!is_inside_scene(),RID()); + return viewport->get_viewport(); +} + +void CanvasItem::set_block_transform_notify(bool p_enable) { + block_transform_notify=p_enable; +} + +bool CanvasItem::is_block_transform_notify_enabled() const { + + return block_transform_notify; +} + +void CanvasItem::set_on_top(bool p_on_top) { + + if (on_top==p_on_top) + return; + on_top=p_on_top; + VisualServer::get_singleton()->canvas_item_set_on_top(canvas_item,on_top); +} + +bool CanvasItem::is_on_top() const { + + return on_top; +} + + +void CanvasItem::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_sort_children"),&CanvasItem::_sort_children); + ObjectTypeDB::bind_method(_MD("_raise_self"),&CanvasItem::_raise_self); + ObjectTypeDB::bind_method(_MD("_update_callback"),&CanvasItem::_update_callback); + ObjectTypeDB::bind_method(_MD("_set_visible_"),&CanvasItem::_set_visible_); + ObjectTypeDB::bind_method(_MD("_is_visible_"),&CanvasItem::_is_visible_); + + ObjectTypeDB::bind_method(_MD("edit_set_state","state"),&CanvasItem::edit_set_state); + ObjectTypeDB::bind_method(_MD("edit_get"),&CanvasItem::edit_get_state); + ObjectTypeDB::bind_method(_MD("edit_set_rect","rect"),&CanvasItem::edit_set_rect); + ObjectTypeDB::bind_method(_MD("edit_rotate","degrees"),&CanvasItem::edit_rotate); + + ObjectTypeDB::bind_method(_MD("get_item_rect"),&CanvasItem::get_item_rect); + //ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform); + ObjectTypeDB::bind_method(_MD("get_canvas_item"),&CanvasItem::get_canvas_item); + + ObjectTypeDB::bind_method(_MD("is_visible"),&CanvasItem::is_visible); + ObjectTypeDB::bind_method(_MD("is_hidden"),&CanvasItem::is_hidden); + ObjectTypeDB::bind_method(_MD("show"),&CanvasItem::show); + ObjectTypeDB::bind_method(_MD("hide"),&CanvasItem::hide); + + ObjectTypeDB::bind_method(_MD("update"),&CanvasItem::update); + + ObjectTypeDB::bind_method(_MD("set_as_toplevel","enable"),&CanvasItem::set_as_toplevel); + ObjectTypeDB::bind_method(_MD("is_set_as_toplevel"),&CanvasItem::is_set_as_toplevel); + + ObjectTypeDB::bind_method(_MD("set_blend_mode","blend_mode"),&CanvasItem::set_blend_mode); + ObjectTypeDB::bind_method(_MD("get_blend_mode"),&CanvasItem::get_blend_mode); + + ObjectTypeDB::bind_method(_MD("set_opacity","opacity"),&CanvasItem::set_opacity); + ObjectTypeDB::bind_method(_MD("get_opacity"),&CanvasItem::get_opacity); + ObjectTypeDB::bind_method(_MD("set_self_opacity","self_opacity"),&CanvasItem::set_self_opacity); + ObjectTypeDB::bind_method(_MD("get_self_opacity"),&CanvasItem::get_self_opacity); + + ObjectTypeDB::bind_method(_MD("set_on_top","on_top"),&CanvasItem::set_on_top); + ObjectTypeDB::bind_method(_MD("is_on_top"),&CanvasItem::is_on_top); + + //ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform); + + ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0)); + ObjectTypeDB::bind_method(_MD("draw_rect","rect","color"),&CanvasItem::draw_rect); + ObjectTypeDB::bind_method(_MD("draw_circle","pos","radius","color"),&CanvasItem::draw_circle); + ObjectTypeDB::bind_method(_MD("draw_texture","texture:Texture","pos"),&CanvasItem::draw_texture); + ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate"),&CanvasItem::draw_texture_rect,DEFVAL(false),DEFVAL(Color(1,1,1))); + ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1))); + ObjectTypeDB::bind_method(_MD("draw_style_box","style_box:StyleBox","rect"),&CanvasItem::draw_style_box); + ObjectTypeDB::bind_method(_MD("draw_primitive","points","colors","uvs","texture:Texture","width"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()),DEFVAL(1.0)); + ObjectTypeDB::bind_method(_MD("draw_polygon","points","colors","uvs","texture:Texture"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>())); + ObjectTypeDB::bind_method(_MD("draw_colored_polygon","points","color","uvs","texture:Texture"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>())); + ObjectTypeDB::bind_method(_MD("draw_string","font:Font","pos","text","modulate","clip_w"),&CanvasItem::draw_string,DEFVAL(Color(1,1,1)),DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("draw_char","font:Font","pos","char","next","modulate"),&CanvasItem::draw_char,DEFVAL(Color(1,1,1))); + + ObjectTypeDB::bind_method(_MD("draw_set_transform","pos","rot","scale"),&CanvasItem::draw_set_transform); + ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform); + ObjectTypeDB::bind_method(_MD("get_global_transform"),&CanvasItem::get_global_transform); + ObjectTypeDB::bind_method(_MD("get_viewport_transform"),&CanvasItem::get_viewport_transform); + ObjectTypeDB::bind_method(_MD("get_viewport_rect"),&CanvasItem::get_viewport_rect); + ObjectTypeDB::bind_method(_MD("get_canvas"),&CanvasItem::get_canvas); + ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d); + ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport); + + BIND_VMETHOD(MethodInfo("_draw")); + + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top"), _SCS("set_on_top"),_SCS("is_on_top") ); + + ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul"), _SCS("set_blend_mode"),_SCS("get_blend_mode") ); + //exporting these two things doesn't really make much sense i think + //ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") ); + //ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled")); + + ADD_SIGNAL( MethodInfo("draw") ); + ADD_SIGNAL( MethodInfo("visibility_changed") ); + ADD_SIGNAL( MethodInfo("hide") ); + ADD_SIGNAL( MethodInfo("item_rect_changed") ); + + + + BIND_CONSTANT( BLEND_MODE_MIX ); + BIND_CONSTANT( BLEND_MODE_ADD ); + BIND_CONSTANT( BLEND_MODE_SUB ); + BIND_CONSTANT( BLEND_MODE_MUL ); + + + BIND_CONSTANT( NOTIFICATION_DRAW); + BIND_CONSTANT( NOTIFICATION_VISIBILITY_CHANGED ); + BIND_CONSTANT( NOTIFICATION_ENTER_CANVAS ); + BIND_CONSTANT( NOTIFICATION_EXIT_CANVAS ); + BIND_CONSTANT( NOTIFICATION_TRANSFORM_CHANGED ); + + +} + +Matrix32 CanvasItem::get_viewport_transform() const { + + ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); + + if (canvas_layer) { + + if (viewport) { + return viewport->get_final_transform() * canvas_layer->get_transform(); + } else { + return canvas_layer->get_transform(); + } + + } else if (viewport) { + return viewport->get_final_transform() * viewport->get_canvas_transform(); + } + + return Matrix32(); + +} + + +CanvasItem::CanvasItem() : xform_change(this) { + + + canvas_item=VisualServer::get_singleton()->canvas_item_create(); + hidden=false; + pending_update=false; + opacity=1; + self_opacity=1; + toplevel=false; + pending_children_sort=false; + first_draw=false; + blend_mode=BLEND_MODE_MIX; + drawing=false; + on_top=true; + block_transform_notify=false; + viewport=NULL; + canvas_layer=NULL; + global_invalid=true; + + C=NULL; + +} + +CanvasItem::~CanvasItem() { + + VisualServer::get_singleton()->free(canvas_item); +} diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h new file mode 100644 index 0000000000..0da4aa3086 --- /dev/null +++ b/scene/2d/canvas_item.h @@ -0,0 +1,209 @@ +/*************************************************************************/ +/* canvas_item.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef CANVAS_ITEM_H +#define CANVAS_ITEM_H + +#include "scene/main/node.h" +#include "scene/resources/texture.h" +#include "scene/main/scene_main_loop.h" + +class CanvasLayer; +class Viewport; +class Font; + +class StyleBox; + +class CanvasItem : public Node { + + OBJ_TYPE( CanvasItem, Node ); +public: + + enum BlendMode { + + BLEND_MODE_MIX, //default + BLEND_MODE_ADD, + BLEND_MODE_SUB, + BLEND_MODE_MUL + }; + +private: + + mutable SelfList<Node> xform_change; + + RID canvas_item; + String group; + + Viewport *viewport; + CanvasLayer *canvas_layer; + + float opacity; + float self_opacity; + + List<CanvasItem*> children_items; + List<CanvasItem*>::Element *C; + + BlendMode blend_mode; + + bool first_draw; + bool hidden; + bool pending_update; + bool toplevel; + bool pending_children_sort; + bool drawing; + bool block_transform_notify; + bool on_top; + + mutable Matrix32 global_transform; + mutable bool global_invalid; + + + void _raise_self(); + + void _propagate_visibility_changed(bool p_visible); + + void _set_visible_(bool p_visible); + bool _is_visible_() const; + + void _update_callback(); + + void _enter_canvas(); + void _exit_canvas(); + + void _queue_sort_children(); + void _sort_children(); + + + + void _notify_transform(CanvasItem *p_node); + +protected: + + + + _FORCE_INLINE_ void _notify_transform() { if (!is_inside_scene()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } + + void item_rect_changed(); + + void _notification(int p_what); + static void _bind_methods(); +public: + + + enum { + NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, //unique + NOTIFICATION_DRAW=30, + NOTIFICATION_VISIBILITY_CHANGED=31, + NOTIFICATION_ENTER_CANVAS=32, + NOTIFICATION_EXIT_CANVAS=33, + NOTIFICATION_LOCAL_TRANSFORM_CHANGED=35, + NOTIFICATION_WORLD_2D_CHANGED=36, + + }; + + /* EDITOR */ + + virtual Variant edit_get_state() const; + virtual void edit_set_state(const Variant& p_state); + virtual void edit_set_rect(const Rect2& p_edit_rect); + virtual void edit_rotate(float p_rot); + virtual Size2 edit_get_minimum_size() const; + + /* VISIBILITY */ + + bool is_visible() const; + bool is_hidden() const; + void show(); + void hide(); + + void update(); + + void set_blend_mode(BlendMode p_blend_mode); + BlendMode get_blend_mode() const; + + void set_opacity(float p_opacity); + float get_opacity() const; + + void set_self_opacity(float p_self_opacity); + float get_self_opacity() const; + + /* DRAWING API */ + + void draw_line(const Point2& p_from, const Point2& p_to,const Color& p_color,float p_width=1.0); + void draw_rect(const Rect2& p_rect, const Color& p_color); + void draw_circle(const Point2& p_pos, float p_radius, const Color& p_color); + void draw_texture(const Ref<Texture>& p_texture,const Point2& p_pos); + void draw_texture_rect(const Ref<Texture>& p_texture, const Rect2& p_rect, bool p_tile=false,const Color& p_modulate=Color(1,1,1)); + void draw_texture_rect_region(const Ref<Texture>& p_texture,const Rect2& p_rect, const Rect2& p_src_rect,const Color& p_modulate=Color(1,1,1)); + void draw_style_box(const Ref<StyleBox>& p_style_box,const Rect2& p_rect); + void draw_primitive(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs, Ref<Texture> p_texture=Ref<Texture>(),float p_width=1); + void draw_polygon(const Vector<Point2>& p_points, const Vector<Color>& p_colors,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>()); + void draw_colored_polygon(const Vector<Point2>& p_points, const Color& p_color,const Vector<Point2>& p_uvs=Vector<Point2>(), Ref<Texture> p_texture=Ref<Texture>()); + + void draw_string(const Ref<Font>& p_font, const Point2& p_pos, const String& p_text,const Color& p_modulate=Color(1,1,1),int p_clip_w=-1); + float draw_char(const Ref<Font>& p_font,const Point2& p_pos, const String& p_char,const String& p_next="",const Color& p_modulate=Color(1,1,1)); + + void draw_set_transform(const Point2& p_offset, float p_rot, const Size2& p_scale); + + /* RECT / TRANSFORM */ + + void set_as_toplevel(bool p_toplevel); + bool is_set_as_toplevel() const; + + void set_on_top(bool p_on_top); + bool is_on_top() const; + + CanvasItem *get_parent_item() const; + + virtual Rect2 get_item_rect() const=0; + virtual Matrix32 get_transform() const=0; + + virtual Matrix32 get_global_transform() const; + virtual Matrix32 get_global_transform_with_canvas() const; + + CanvasItem *get_toplevel() const; + _FORCE_INLINE_ RID get_canvas_item() const { return canvas_item; } + + void set_block_transform_notify(bool p_enable); + bool is_block_transform_notify_enabled() const; + + Matrix32 get_viewport_transform() const; + Rect2 get_viewport_rect() const; + RID get_viewport_rid() const; + RID get_canvas() const; + Ref<World2D> get_world_2d() const; + Viewport *get_viewport() const; + + + CanvasItem(); + ~CanvasItem(); +}; + +VARIANT_ENUM_CAST( CanvasItem::BlendMode ); + +#endif // CANVAS_ITEM_H diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp new file mode 100644 index 0000000000..ab8c4551ee --- /dev/null +++ b/scene/2d/collision_object_2d.cpp @@ -0,0 +1,282 @@ +/*************************************************************************/ +/* collision_object_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "collision_object_2d.h" +#include "servers/physics_2d_server.h" + +void CollisionObject2D::_update_shapes_from_children() { + + shapes.resize(0); + for(int i=0;i<get_child_count();i++) { + + Node* n = get_child(i); + n->call("_add_to_collision_object",this); + } + +// _update_shapes(); +} + +void CollisionObject2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + + RID space = get_world_2d()->get_space(); + if (area) { + Physics2DServer::get_singleton()->area_set_space(rid,space); + } else + Physics2DServer::get_singleton()->body_set_space(rid,space); + + //get space + } + + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (area) + Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform()); + else + Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform()); + + } break; + case NOTIFICATION_EXIT_SCENE: { + + if (area) { + Physics2DServer::get_singleton()->area_set_space(rid,RID()); + } else + Physics2DServer::get_singleton()->body_set_space(rid,RID()); + + } break; + } +} + +void CollisionObject2D::_update_shapes() { + + if (!rid.is_valid()) + return; + + if (area) + Physics2DServer::get_singleton()->area_clear_shapes(rid); + else + Physics2DServer::get_singleton()->body_clear_shapes(rid); + + for(int i=0;i<shapes.size();i++) { + + if (shapes[i].shape.is_null()) + continue; + if (area) + Physics2DServer::get_singleton()->area_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform); + else { + Physics2DServer::get_singleton()->body_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform); + if (shapes[i].trigger) + Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger); + } + } +} + + +bool CollisionObject2D::_set(const StringName& p_name, const Variant& p_value) { + String name=p_name; + + if (name=="shape_count") { + + shapes.resize(p_value); + _update_shapes(); + _change_notify(); + + } else if (name.begins_with("shapes/")) { + + int idx=name.get_slice("/",1).to_int(); + String what=name.get_slice("/",2); + if (what=="shape") + set_shape(idx,RefPtr(p_value)); + else if (what=="transform") + set_shape_transform(idx,p_value); + else if (what=="trigger") + set_shape_as_trigger(idx,p_value); + } else + return false; + + return true; + + +} + +bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const { + + String name=p_name; + + if (name=="shape_count") { + r_ret= shapes.size(); + } else if (name.begins_with("shapes/")) { + + int idx=name.get_slice("/",1).to_int(); + String what=name.get_slice("/",2); + if (what=="shape") + r_ret= get_shape(idx); + else if (what=="transform") + r_ret= get_shape_transform(idx); + else if (what=="trigger") + r_ret= is_shape_set_as_trigger(idx); + } else + return false; + + return true; +} + +void CollisionObject2D::_get_property_list( List<PropertyInfo> *p_list) const { + + p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR) ); + + for(int i=0;i<shapes.size();i++) { + String path="shapes/"+itos(i)+"/"; + p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); + } +} + +void CollisionObject2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("add_shape","shape:Shape2D","transform"),&CollisionObject2D::add_shape,DEFVAL(Matrix32())); + ObjectTypeDB::bind_method(_MD("get_shape_count"),&CollisionObject2D::get_shape_count); + ObjectTypeDB::bind_method(_MD("set_shape","shape_idx","shape:Shape"),&CollisionObject2D::set_shape); + ObjectTypeDB::bind_method(_MD("set_shape_transform","shape_idx","transform"),&CollisionObject2D::set_shape_transform); + ObjectTypeDB::bind_method(_MD("set_shape_as_trigger","shape_idx","enable"),&CollisionObject2D::set_shape_as_trigger); + ObjectTypeDB::bind_method(_MD("get_shape:Shape2D","shape_idx"),&CollisionObject2D::get_shape); + ObjectTypeDB::bind_method(_MD("get_shape_transform","shape_idx"),&CollisionObject2D::get_shape_transform); + ObjectTypeDB::bind_method(_MD("is_shape_set_as_trigger","shape_idx"),&CollisionObject2D::is_shape_set_as_trigger); + ObjectTypeDB::bind_method(_MD("remove_shape","shape_idx"),&CollisionObject2D::remove_shape); + ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject2D::clear_shapes); + ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject2D::get_rid); + +} + + +void CollisionObject2D::add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform) { + + ShapeData sdata; + sdata.shape=p_shape; + sdata.xform=p_transform; + sdata.trigger=false; + shapes.push_back(sdata); + _update_shapes(); + +} +int CollisionObject2D::get_shape_count() const { + + return shapes.size(); + +} +void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes[p_shape_idx].shape=p_shape; + _update_shapes(); +} + +void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_transform) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes[p_shape_idx].xform=p_transform; + + _update_shapes(); +} + +Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const { + + ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Ref<Shape2D>()); + return shapes[p_shape_idx].shape; + +} +Matrix32 CollisionObject2D::get_shape_transform(int p_shape_idx) const { + + ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),Matrix32()); + return shapes[p_shape_idx].xform; + +} +void CollisionObject2D::remove_shape(int p_shape_idx) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes.remove(p_shape_idx); + + _update_shapes(); +} + +void CollisionObject2D::set_shape_as_trigger(int p_shape_idx, bool p_trigger) { + + ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + shapes[p_shape_idx].trigger=p_trigger; + if (!area && rid.is_valid()) { + + Physics2DServer::get_singleton()->body_set_shape_as_trigger(rid,p_shape_idx,p_trigger); + + } +} + +bool CollisionObject2D::is_shape_set_as_trigger(int p_shape_idx) const { + + ERR_FAIL_INDEX_V(p_shape_idx,shapes.size(),false); + return shapes[p_shape_idx].trigger; +} + +void CollisionObject2D::clear_shapes() { + + shapes.clear(); + + _update_shapes(); +} + + +CollisionObject2D::CollisionObject2D(RID p_rid, bool p_area) { + + rid=p_rid; + area=p_area; + if (p_area) { + Physics2DServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID()); + } else { + Physics2DServer::get_singleton()->body_attach_object_instance_ID(rid,get_instance_ID()); + } + + +} + + +CollisionObject2D::CollisionObject2D() { + + + //owner= + + +} + +CollisionObject2D::~CollisionObject2D() { + + Physics2DServer::get_singleton()->free(rid); +} diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h new file mode 100644 index 0000000000..4a529ce062 --- /dev/null +++ b/scene/2d/collision_object_2d.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* collision_object_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef COLLISION_OBJECT_2D_H +#define COLLISION_OBJECT_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/shape_2d.h" + +class CollisionObject2D : public Node2D { + + OBJ_TYPE( CollisionObject2D, Node2D ); + + bool area; + RID rid; + + struct ShapeData { + Matrix32 xform; + Ref<Shape2D> shape; + bool trigger; + + ShapeData() { + trigger=false; + } + }; + + + Vector<ShapeData> shapes; + + void _update_shapes(); + +friend class CollisionShape2D; +friend class CollisionPolygon2D; + void _update_shapes_from_children(); +protected: + + CollisionObject2D(RID p_rid, bool p_area); + + void _notification(int p_what); + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list( List<PropertyInfo> *p_list) const; + static void _bind_methods(); +public: + + + void add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform=Matrix32()); + int get_shape_count() const; + void set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape); + void set_shape_transform(int p_shape_idx, const Matrix32& p_transform); + Ref<Shape2D> get_shape(int p_shape_idx) const; + Matrix32 get_shape_transform(int p_shape_idx) const; + void set_shape_as_trigger(int p_shape_idx, bool p_trigger); + bool is_shape_set_as_trigger(int p_shape_idx) const; + void remove_shape(int p_shape_idx); + void clear_shapes(); + + _FORCE_INLINE_ RID get_rid() const { return rid; } + + CollisionObject2D(); + ~CollisionObject2D(); +}; + +#endif // COLLISION_OBJECT_2D_H diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp new file mode 100644 index 0000000000..5ab223a1b8 --- /dev/null +++ b/scene/2d/collision_polygon_2d.cpp @@ -0,0 +1,187 @@ +/*************************************************************************/ +/* collision_polygon_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "collision_polygon_2d.h" +#include "collision_object_2d.h" +#include "scene/resources/concave_polygon_shape_2d.h" +#include "scene/resources/convex_polygon_shape_2d.h" + +void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { + + CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); + ERR_FAIL_COND(!co); + + if (polygon.size()==0) + return; + + bool solids=build_mode==BUILD_SOLIDS; + + + if (solids) { + + //here comes the sun, lalalala + //decompose concave into multiple convex polygons and add them + Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon); + for(int i=0;i<decomp.size();i++) { + Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D ); + convex->set_points(decomp[i]); + co->add_shape(convex,get_transform()); + + } + + } else { + + Ref<ConcavePolygonShape2D> concave = memnew( ConcavePolygonShape2D ); + + DVector<Vector2> segments; + segments.resize(polygon.size()*2); + DVector<Vector2>::Write w=segments.write(); + + for(int i=0;i<polygon.size();i++) { + w[(i<<1)+0]=polygon[i]; + w[(i<<1)+1]=polygon[(i+1)%polygon.size()]; + } + + w=DVector<Vector2>::Write(); + concave->set_segments(segments); + + co->add_shape(concave,get_transform()); + + } + + + //co->add_shape(shape,get_transform()); +} + +void CollisionPolygon2D::_update_parent() { + + Node *parent = get_parent(); + if (!parent) + return; + CollisionObject2D *co = parent->cast_to<CollisionObject2D>(); + if (!co) + return; + co->_update_shapes_from_children(); +} + +void CollisionPolygon2D::_notification(int p_what) { + + + switch(p_what) { + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + + if (!is_inside_scene()) + break; + _update_parent(); + + } break; + + case NOTIFICATION_DRAW: { + for(int i=0;i<polygon.size();i++) { + + Vector2 p = polygon[i]; + Vector2 n = polygon[(i+1)%polygon.size()]; + draw_line(p,n,Color(0,0.6,0.7,0.5),3); + } + + Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon); +#define DEBUG_DECOMPOSE +#ifdef DEBUG_DECOMPOSE + Color c(0.4,0.9,0.1); + for(int i=0;i<decomp.size();i++) { + + c.set_hsv( Math::fmod(c.get_h() + 0.738,1),c.get_s(),c.get_v(),0.5); + draw_colored_polygon(decomp[i],c); + } +#endif + } break; + } +} + +void CollisionPolygon2D::set_polygon(const Vector<Point2>& p_polygon) { + + polygon=p_polygon; + + for(int i=0;i<polygon.size();i++) { + if (i==0) + aabb=Rect2(polygon[i],Size2()); + else + aabb.expand_to(polygon[i]); + } + if (aabb==Rect2()) { + + aabb=Rect2(-10,-10,20,20); + } else { + aabb.pos-=aabb.size*0.3; + aabb.size+=aabb.size*0.6; + } + _update_parent(); + update(); +} + +Vector<Point2> CollisionPolygon2D::get_polygon() const { + + return polygon; +} + +void CollisionPolygon2D::set_build_mode(BuildMode p_mode) { + + ERR_FAIL_INDEX(p_mode,2); + build_mode=p_mode; +} + +CollisionPolygon2D::BuildMode CollisionPolygon2D::get_build_mode() const{ + + return build_mode; +} + +Rect2 CollisionPolygon2D::get_item_rect() const { + + return aabb; +} + +void CollisionPolygon2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object); + ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon2D::set_polygon); + ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon2D::get_polygon); + + ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode); + ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Automatic,Segments,Solids"),_SCS("set_build_mode"),_SCS("get_build_mode")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); +} + +CollisionPolygon2D::CollisionPolygon2D() { + + aabb=Rect2(-10,-10,20,20); + build_mode=BUILD_SOLIDS; + + +} diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h new file mode 100644 index 0000000000..09c2060088 --- /dev/null +++ b/scene/2d/collision_polygon_2d.h @@ -0,0 +1,75 @@ +/*************************************************************************/ +/* collision_polygon_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef COLLISION_POLYGON_2D_H +#define COLLISION_POLYGON_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/shape_2d.h" + + + +class CollisionPolygon2D : public Node2D { + + OBJ_TYPE(CollisionPolygon2D,Node2D); +public: + + enum BuildMode { + BUILD_SOLIDS, + BUILD_SEGMENTS, + }; + +protected: + + + Rect2 aabb; + BuildMode build_mode; + Vector<Point2> polygon; + + void _add_to_collision_object(Object *p_obj); + void _update_parent(); + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_build_mode(BuildMode p_mode); + BuildMode get_build_mode() const; + + void set_polygon(const Vector<Point2>& p_polygon); + Vector<Point2> get_polygon() const; + + virtual Rect2 get_item_rect() const; + CollisionPolygon2D(); +}; + +VARIANT_ENUM_CAST( CollisionPolygon2D::BuildMode ); + +#endif // COLLISION_POLYGON_2D_H diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp new file mode 100644 index 0000000000..4ae9b37c21 --- /dev/null +++ b/scene/2d/collision_shape_2d.cpp @@ -0,0 +1,248 @@ +/*************************************************************************/ +/* collision_shape_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "collision_shape_2d.h" +#include "collision_object_2d.h" +#include "scene/resources/segment_shape_2d.h" +#include "scene/resources/shape_line_2d.h" +#include "scene/resources/circle_shape_2d.h" +#include "scene/resources/rectangle_shape_2d.h" +#include "scene/resources/capsule_shape_2d.h" +#include "scene/resources/convex_polygon_shape_2d.h" +#include "scene/resources/concave_polygon_shape_2d.h" + + +void CollisionShape2D::_add_to_collision_object(Object *p_obj) { + + CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); + ERR_FAIL_COND(!co); + co->add_shape(shape,get_transform()); + if (trigger) + co->set_shape_as_trigger(co->get_shape_count()-1,true); + +} + +void CollisionShape2D::_shape_changed() { + + update(); + _update_parent(); +} + +void CollisionShape2D::_update_parent() { + + + Node *parent = get_parent(); + if (!parent) + return; + CollisionObject2D *co = parent->cast_to<CollisionObject2D>(); + if (!co) + return; + co->_update_shapes_from_children(); +} + +void CollisionShape2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + + if (!is_inside_scene()) + break; + _update_parent(); + + } break; + /* + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (!is_inside_scene()) + break; + _update_parent(); + + } break;*/ + case NOTIFICATION_DRAW: { + + rect=Rect2(); + + Color draw_col=Color(0,0.6,0.7,0.5); + + if (shape->cast_to<LineShape2D>()) { + + LineShape2D *l = shape->cast_to<LineShape2D>(); + Vector2 point = l->get_d() * l->get_normal(); + + Vector2 l1[2]={point-l->get_normal().tangent()*100,point+l->get_normal().tangent()*100}; + draw_line(l1[0],l1[1],draw_col,3); + Vector2 l2[2]={point,point+l->get_normal()*30}; + draw_line(l2[0],l2[1],draw_col,3); + rect.pos=l1[0]; + rect.expand_to(l1[1]); + rect.expand_to(l2[0]); + rect.expand_to(l2[1]); + + } else if (shape->cast_to<SegmentShape2D>()) { + + SegmentShape2D *s = shape->cast_to<SegmentShape2D>(); + draw_line(s->get_a(),s->get_b(),draw_col,3); + rect.pos=s->get_a(); + rect.expand_to(s->get_b()); + + } else if (shape->cast_to<RayShape2D>()) { + + RayShape2D *s = shape->cast_to<RayShape2D>(); + + Vector2 tip = Vector2(0,s->get_length()); + draw_line(Vector2(),tip,draw_col,3); + Vector<Vector2> pts; + float tsize=4; + pts.push_back(tip+Vector2(0,tsize)); + pts.push_back(tip+Vector2(0.707*tsize,0)); + pts.push_back(tip+Vector2(-0.707*tsize,0)); + Vector<Color> cols; + for(int i=0;i<3;i++) + cols.push_back(draw_col); + + draw_primitive(pts,cols,Vector<Vector2>()); //small arrow + + rect.pos=Vector2(); + rect.expand_to(tip); + rect=rect.grow(0.707*tsize); + + } else if (shape->cast_to<CircleShape2D>()) { + + CircleShape2D *s = shape->cast_to<CircleShape2D>(); + Vector<Vector2> points; + for(int i=0;i<24;i++) { + + points.push_back(Vector2(Math::cos(i*Math_PI*2/24.0),Math::sin(i*Math_PI*2/24.0))*s->get_radius()); + } + + draw_colored_polygon(points,draw_col); + rect.pos=-Point2(s->get_radius(),s->get_radius()); + rect.size=Point2(s->get_radius(),s->get_radius())*2.0; + + } else if (shape->cast_to<RectangleShape2D>()) { + + RectangleShape2D *s = shape->cast_to<RectangleShape2D>(); + Vector2 he = s->get_extents(); + rect=Rect2(-he,he*2.0); + draw_rect(rect,draw_col);; + + } else if (shape->cast_to<CapsuleShape2D>()) { + + CapsuleShape2D *s = shape->cast_to<CapsuleShape2D>(); + + Vector<Vector2> points; + for(int i=0;i<24;i++) { + Vector2 ofs = Vector2(0,(i>6 && i<=18) ? -s->get_height()*0.5 : s->get_height()*0.5); + + points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() + ofs); + if (i==6 || i==18) + points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() - ofs); + } + + draw_colored_polygon(points,draw_col); + Vector2 he=Point2(s->get_radius(),s->get_radius()+s->get_height()*0.5); + rect.pos=-he; + rect.size=he*2.0; + + } else if (shape->cast_to<ConvexPolygonShape2D>()) { + + ConvexPolygonShape2D *s = shape->cast_to<ConvexPolygonShape2D>(); + + Vector<Vector2> points = s->get_points(); + for(int i=0;i<points.size();i++) { + if (i==0) + rect.pos=points[i]; + else + rect.expand_to(points[i]); + } + + draw_colored_polygon(points,draw_col); + + } + + rect=rect.grow(3); + + } break; + + } + +} + +void CollisionShape2D::set_shape(const Ref<Shape2D>& p_shape) { + + if (shape.is_valid()) + shape->disconnect("changed",this,"_shape_changed"); + shape=p_shape; + update(); + _update_parent(); + if (shape.is_valid()) + shape->connect("changed",this,"_shape_changed"); + +} + +Ref<Shape2D> CollisionShape2D::get_shape() const { + + return shape; +} + +Rect2 CollisionShape2D::get_item_rect() const { + + return rect; +} + +void CollisionShape2D::set_trigger(bool p_trigger) { + + trigger=p_trigger; + _update_parent(); +} + +bool CollisionShape2D::is_trigger() const{ + + return trigger; +} + +void CollisionShape2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape2D::set_shape); + ObjectTypeDB::bind_method(_MD("get_shape"),&CollisionShape2D::get_shape); + ObjectTypeDB::bind_method(_MD("_shape_changed"),&CollisionShape2D::_shape_changed); + ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionShape2D::_add_to_collision_object); + ObjectTypeDB::bind_method(_MD("set_trigger","enable"),&CollisionShape2D::set_trigger); + ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape2D::is_trigger); + + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D"),_SCS("set_shape"),_SCS("get_shape")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); +} + +CollisionShape2D::CollisionShape2D() { + + rect=Rect2(-Point2(10,10),Point2(20,20)); + + trigger=false; +} diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h new file mode 100644 index 0000000000..2e2023f54d --- /dev/null +++ b/scene/2d/collision_shape_2d.h @@ -0,0 +1,61 @@ +/*************************************************************************/ +/* collision_shape_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef COLLISION_SHAPE_2D_H +#define COLLISION_SHAPE_2D_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/shape_2d.h" + +class CollisionShape2D : public Node2D { + + OBJ_TYPE(CollisionShape2D,Node2D); + Ref<Shape2D> shape; + Rect2 rect; + bool trigger; + + void _shape_changed(); +protected: + + void _update_parent(); + void _notification(int p_what); + static void _bind_methods(); + + void _add_to_collision_object(Object *p_obj); +public: + + void set_shape(const Ref<Shape2D>& p_shape); + Ref<Shape2D> get_shape() const; + virtual Rect2 get_item_rect() const; + void set_trigger(bool p_trigger); + bool is_trigger() const; + + CollisionShape2D(); +}; + +#endif // COLLISION_SHAPE_2D_H diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp new file mode 100644 index 0000000000..0e673ff791 --- /dev/null +++ b/scene/2d/joints_2d.cpp @@ -0,0 +1,412 @@ +/*************************************************************************/ +/* joints_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "joints_2d.h" +#include "servers/physics_2d_server.h" +#include "physics_body_2d.h" + +void Joint2D::_update_joint() { + + if (!is_inside_scene()) + return; + + if (joint.is_valid()) { + Physics2DServer::get_singleton()->free(joint); + } + + joint=RID(); + + + joint = _configure_joint(); + Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint,Physics2DServer::JOINT_PARAM_BIAS,bias); + + +} + + +void Joint2D::set_node_a(const NodePath& p_node_a) { + + + if (a==p_node_a) + return; + + a=p_node_a; + _update_joint(); +} + +NodePath Joint2D::get_node_a() const{ + + return a; +} + +void Joint2D::set_node_b(const NodePath& p_node_b){ + + if (b==p_node_b) + return; + b=p_node_b; + _update_joint(); + +} +NodePath Joint2D::get_node_b() const{ + + + return b; +} + + +void Joint2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_READY: { + _update_joint(); + } break; + case NOTIFICATION_EXIT_SCENE: { + if (joint.is_valid()) { + + Physics2DServer::get_singleton()->free(joint); + joint=RID(); + } + } break; + + } + +} + +void Joint2D::set_bias(real_t p_bias) { + + bias=p_bias; + if (joint.is_valid()) + Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint,Physics2DServer::JOINT_PARAM_BIAS,bias); +} + +real_t Joint2D::get_bias() const{ + + + return bias; +} + + +void Joint2D::_bind_methods() { + + + ObjectTypeDB::bind_method( _MD("set_node_a","node"), &Joint2D::set_node_a ); + ObjectTypeDB::bind_method( _MD("get_node_a"), &Joint2D::get_node_a ); + + ObjectTypeDB::bind_method( _MD("set_node_b","node"), &Joint2D::set_node_b ); + ObjectTypeDB::bind_method( _MD("get_node_b"), &Joint2D::get_node_b ); + + ObjectTypeDB::bind_method( _MD("set_bias","bias"), &Joint2D::set_bias ); + ObjectTypeDB::bind_method( _MD("get_bias"), &Joint2D::get_bias ); + + ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_a"), _SCS("set_node_a"),_SCS("get_node_a") ); + ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_b"), _SCS("set_node_b"),_SCS("get_node_b") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.01"), _SCS("set_bias"),_SCS("get_bias") ); + +} + + + +Joint2D::Joint2D() { + + bias=0; +} + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + +void PinJoint2D::_notification(int p_what) { + + switch(p_what) { + case NOTIFICATION_DRAW: { + if (is_inside_scene() && get_scene()->is_editor_hint()) { + + draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3); + draw_line(Point2(0,-10),Point2(0,+10),Color(0.7,0.6,0.0,0.5),3); + } + } break; + } + +} + +RID PinJoint2D::_configure_joint() { + + Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; + Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL; + + if (!node_a && !node_b) + return RID(); + + PhysicsBody2D *body_a=node_a ? node_a->cast_to<PhysicsBody2D>() : (PhysicsBody2D*)NULL; + PhysicsBody2D *body_b=node_b ? node_b->cast_to<PhysicsBody2D>() : (PhysicsBody2D*)NULL; + + if (!body_a && !body_b) + return RID(); + + if (!body_a) { + SWAP(body_a,body_b); + } else if (body_b) { + //add a collision exception between both + Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); + } + + return Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID()); + +} + + +PinJoint2D::PinJoint2D() { + + +} + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + +void GrooveJoint2D::_notification(int p_what) { + + switch(p_what) { + case NOTIFICATION_DRAW: { + if (is_inside_scene() && get_scene()->is_editor_hint()) { + + draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3); + draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3); + draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3); + draw_line(Point2(-10,initial_offset),Point2(+10,initial_offset),Color(0.8,0.8,0.9,0.5),5); + } + } break; + } +} + +RID GrooveJoint2D::_configure_joint(){ + + + Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; + Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL; + + if (!node_a || !node_b) + return RID(); + + PhysicsBody2D *body_a=node_a->cast_to<PhysicsBody2D>(); + PhysicsBody2D *body_b=node_b->cast_to<PhysicsBody2D>(); + + if (!body_a || !body_b) + return RID(); + + Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); + + Matrix32 gt = get_global_transform(); + Vector2 groove_A1 = gt.get_origin(); + Vector2 groove_A2 = gt.xform( Vector2(0,length) ); + Vector2 anchor_B = gt.xform( Vector2(0,initial_offset) ); + + + return Physics2DServer::get_singleton()->groove_joint_create(groove_A1,groove_A2,anchor_B,body_a->get_rid(),body_b->get_rid()); +} + + +void GrooveJoint2D::set_length(real_t p_length) { + + length=p_length; + update(); +} + +real_t GrooveJoint2D::get_length() const { + + return length; +} + + +void GrooveJoint2D::set_initial_offset(real_t p_initial_offset) { + + initial_offset=p_initial_offset; + update(); +} + +real_t GrooveJoint2D::get_initial_offset() const { + + return initial_offset; +} + + + +void GrooveJoint2D::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_length","length"),&GrooveJoint2D::set_length); + ObjectTypeDB::bind_method(_MD("get_length"),&GrooveJoint2D::get_length); + ObjectTypeDB::bind_method(_MD("set_initial_offset","offset"),&GrooveJoint2D::set_initial_offset); + ObjectTypeDB::bind_method(_MD("get_initial_offset"),&GrooveJoint2D::get_initial_offset); + + ADD_PROPERTY( PropertyInfo( Variant::REAL, "length", PROPERTY_HINT_EXP_RANGE,"1,65535,1"), _SCS("set_length"),_SCS("get_length")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "initial_offset", PROPERTY_HINT_EXP_RANGE,"1,65535,1"), _SCS("set_initial_offset"),_SCS("get_initial_offset")); +} + +GrooveJoint2D::GrooveJoint2D() { + + length=50; + initial_offset=25; +} + + + + +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////// + + + +void DampedSpringJoint2D::_notification(int p_what) { + + switch(p_what) { + case NOTIFICATION_DRAW: { + if (is_inside_scene() && get_scene()->is_editor_hint()) { + + draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3); + draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3); + draw_line(Point2(0,0),Point2(0,length),Color(0.7,0.6,0.0,0.5),3); + } + } break; + } +} + +RID DampedSpringJoint2D::_configure_joint(){ + + + Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; + Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL; + + if (!node_a || !node_b) + return RID(); + + PhysicsBody2D *body_a=node_a->cast_to<PhysicsBody2D>(); + PhysicsBody2D *body_b=node_b->cast_to<PhysicsBody2D>(); + + if (!body_a || !body_b) + return RID(); + + Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); + + Matrix32 gt = get_global_transform(); + Vector2 anchor_A = gt.get_origin(); + Vector2 anchor_B = gt.xform( Vector2(0,length) ); + + RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A,anchor_B,body_a->get_rid(),body_b->get_rid()); + if (rest_length) + Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_REST_LENGTH,rest_length); + Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_STIFFNESS,stiffness); + Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_DAMPING,damping); + + return dsj; +} + + +void DampedSpringJoint2D::set_length(real_t p_length) { + + length=p_length; + update(); +} + +real_t DampedSpringJoint2D::get_length() const { + + return length; +} + +void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) { + + rest_length=p_rest_length; + update(); + if (get_joint().is_valid()) + Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(),Physics2DServer::DAMPED_STRING_REST_LENGTH,p_rest_length?p_rest_length:length); + +} + +real_t DampedSpringJoint2D::get_rest_length() const { + + return rest_length; +} + +void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) { + + stiffness=p_stiffness; + update(); + if (get_joint().is_valid()) + Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(),Physics2DServer::DAMPED_STRING_STIFFNESS,p_stiffness); +} + +real_t DampedSpringJoint2D::get_stiffness() const { + + return stiffness; +} + +void DampedSpringJoint2D::set_damping(real_t p_damping) { + + damping=p_damping; + update(); + if (get_joint().is_valid()) + Physics2DServer::get_singleton()->damped_string_joint_set_param(get_joint(),Physics2DServer::DAMPED_STRING_DAMPING,p_damping); +} + +real_t DampedSpringJoint2D::get_damping() const { + + return damping; +} + + +void DampedSpringJoint2D::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_length","length"),&DampedSpringJoint2D::set_length); + ObjectTypeDB::bind_method(_MD("get_length"),&DampedSpringJoint2D::get_length); + ObjectTypeDB::bind_method(_MD("set_rest_length","rest_length"),&DampedSpringJoint2D::set_rest_length); + ObjectTypeDB::bind_method(_MD("get_rest_length"),&DampedSpringJoint2D::get_rest_length); + ObjectTypeDB::bind_method(_MD("set_stiffness","stiffness"),&DampedSpringJoint2D::set_stiffness); + ObjectTypeDB::bind_method(_MD("get_stiffness"),&DampedSpringJoint2D::get_stiffness); + ObjectTypeDB::bind_method(_MD("set_damping","damping"),&DampedSpringJoint2D::set_damping); + ObjectTypeDB::bind_method(_MD("get_damping"),&DampedSpringJoint2D::get_damping); + + ADD_PROPERTY( PropertyInfo( Variant::REAL, "length", PROPERTY_HINT_EXP_RANGE,"1,65535,1"), _SCS("set_length"),_SCS("get_length")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "rest_length", PROPERTY_HINT_EXP_RANGE,"0,65535,1"), _SCS("set_rest_length"),_SCS("get_rest_length")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "stiffness", PROPERTY_HINT_EXP_RANGE,"0.1,64,0.1"), _SCS("set_stiffness"),_SCS("get_stiffness")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "damping", PROPERTY_HINT_EXP_RANGE,"0.01,16,0.01"), _SCS("set_damping"),_SCS("get_damping")); + +} + +DampedSpringJoint2D::DampedSpringJoint2D() { + + length=50; + rest_length=0; + stiffness=20; + damping=1; +} diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h new file mode 100644 index 0000000000..7027e4386a --- /dev/null +++ b/scene/2d/joints_2d.h @@ -0,0 +1,141 @@ +/*************************************************************************/ +/* joints_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef JOINTS_2D_H +#define JOINTS_2D_H + + +#include "node_2d.h" + +class Joint2D : public Node2D { + + OBJ_TYPE(Joint2D,Node2D); + + RID joint; + + NodePath a; + NodePath b; + real_t bias; + + +protected: + + void _update_joint(); + + void _notification(int p_what); + virtual RID _configure_joint()=0; + + static void _bind_methods(); +public: + + void set_node_a(const NodePath& p_node_a); + NodePath get_node_a() const; + + void set_node_b(const NodePath& p_node_b); + NodePath get_node_b() const; + + void set_bias(real_t p_bias); + real_t get_bias() const; + + RID get_joint() const { return joint; } + Joint2D(); + +}; + + +class PinJoint2D : public Joint2D { + + OBJ_TYPE(PinJoint2D,Joint2D); + +protected: + + void _notification(int p_what); + virtual RID _configure_joint(); +public: + + + + PinJoint2D(); +}; + +class GrooveJoint2D : public Joint2D { + + OBJ_TYPE(GrooveJoint2D,Joint2D); + + real_t length; + real_t initial_offset; + +protected: + + void _notification(int p_what); + virtual RID _configure_joint(); + static void _bind_methods(); +public: + + void set_length(real_t p_length); + real_t get_length() const; + + void set_initial_offset(real_t p_initial_offset); + real_t get_initial_offset() const; + + GrooveJoint2D(); +}; + +class DampedSpringJoint2D : public Joint2D { + + OBJ_TYPE(DampedSpringJoint2D,Joint2D); + + real_t stiffness; + real_t damping; + real_t rest_length; + real_t length; + +protected: + + void _notification(int p_what); + virtual RID _configure_joint(); + static void _bind_methods(); +public: + + void set_length(real_t p_length); + real_t get_length() const; + + void set_rest_length(real_t p_rest_length); + real_t get_rest_length() const; + + void set_damping(real_t p_damping); + real_t get_damping() const; + + void set_stiffness(real_t p_stiffness); + real_t get_stiffness() const; + + DampedSpringJoint2D(); +}; + + +#endif // JOINTS_2D_H diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp new file mode 100644 index 0000000000..9b2994ef84 --- /dev/null +++ b/scene/2d/node_2d.cpp @@ -0,0 +1,291 @@ +/*************************************************************************/ +/* node_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "node_2d.h" + +#include "servers/visual_server.h" +#include "scene/gui/control.h" +#include "scene/main/viewport.h" +#include "message_queue.h" + + +void Node2D::edit_set_pivot(const Point2& p_pivot) { + + +} + +Point2 Node2D::edit_get_pivot() const { + + return Point2(); +} +bool Node2D::edit_has_pivot() const { + + return false; +} + +Variant Node2D::edit_get_state() const { + + Array state; + state.push_back(pos); + state.push_back(angle); + state.push_back(scale); + + return state; + +} +void Node2D::edit_set_state(const Variant& p_state) { + + Array state = p_state; + ERR_FAIL_COND( state.size() != 3); + + pos = state[0]; + angle = state[1]; + scale = state[2]; + _update_transform(); + _change_notify("transform/rot"); + _change_notify("transform/scale"); + _change_notify("transform/pos"); + +} + +void Node2D::edit_set_rect(const Rect2& p_edit_rect) { + + Rect2 r = get_item_rect(); + + Vector2 zero_offset; + if (r.size.x!=0) + zero_offset.x = -r.pos.x / r.size.x; + if (r.size.y!=0) + zero_offset.y = -r.pos.y / r.size.y; + + Size2 new_scale(1,1); + + if (r.size.x!=0) + new_scale.x = p_edit_rect.size.x / r.size.x; + if (r.size.y!=0) + new_scale.y = p_edit_rect.size.y / r.size.y; + + Point2 new_pos = p_edit_rect.pos + p_edit_rect.size*zero_offset;//p_edit_rect.pos - r.pos; + + Matrix32 postxf; + postxf.set_rotation_and_scale(angle,scale); + new_pos = postxf.xform(new_pos); + + pos+=new_pos; + scale*=new_scale; + + _update_transform(); + _change_notify("transform/scale"); + _change_notify("transform/pos"); + +} + + +void Node2D::edit_rotate(float p_rot) { + + angle+=p_rot; + _update_transform(); + _change_notify("transform/rot"); +} + + +void Node2D::_update_xform_values() { + + pos=_mat.elements[2]; + angle=_mat.get_rotation(); + scale=_mat.get_scale(); + _xform_dirty=false; +} + +void Node2D::_update_transform() { + + Matrix32 mat(angle,pos); + _mat.set_rotation_and_scale(angle,scale); + _mat.elements[2]=pos; + + VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat); + + if (!is_inside_scene()) + return; + + + _notify_transform(); +} + +void Node2D::set_pos(const Point2& p_pos) { + + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); + pos=p_pos; + _update_transform(); + _change_notify("transform/pos"); + + +} + +void Node2D::set_rot(float p_angle) { + + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); + angle=p_angle; + _update_transform(); + _change_notify("transform/rot"); +} + +void Node2D::set_scale(const Size2& p_scale) { + + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); + scale=p_scale; + _update_transform(); + _change_notify("transform/scale"); + +} + +Point2 Node2D::get_pos() const { + + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); + return pos; +} +float Node2D::get_rot() const { + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); + + return angle; +} +Size2 Node2D::get_scale() const { + if (_xform_dirty) + ((Node2D*)this)->_update_xform_values(); + + return scale; +} + +void Node2D::_set_rotd(float p_angle) { + + set_rot(Math::deg2rad(p_angle)); +} + +float Node2D::_get_rotd() const { + + return Math::rad2deg(get_rot()); +} + + +void Node2D::_notification(int p_what) { + + switch(p_what) { + + } +} + +Matrix32 Node2D::get_transform() const { + + return _mat; +} + +Rect2 Node2D::get_item_rect() const { + + if (get_script_instance()) { + Variant::CallError err; + Rect2 r = get_script_instance()->call("_get_item_rect",NULL,0,err); + if (err.error==Variant::CallError::CALL_OK) + return r; + } + return Rect2(Point2(-32,-32),Size2(64,64)); +} + +Point2 Node2D::get_global_pos() const { + + return get_global_transform().get_origin(); +} + +void Node2D::set_transform(const Matrix32& p_transform) { + + _mat=p_transform; + _xform_dirty=true; + + VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat); + + if (!is_inside_scene()) + return; + + _notify_transform(); +} + +void Node2D::set_global_transform(const Matrix32& p_transform) { + + CanvasItem *pi = get_parent_item(); + if (pi) + set_transform( pi->get_global_transform().affine_inverse() * p_transform); + else + set_transform(p_transform); + + +} + +void Node2D::_bind_methods() { + + + + ObjectTypeDB::bind_method(_MD("_get_rotd"),&Node2D::_get_rotd); + ObjectTypeDB::bind_method(_MD("_set_rotd"),&Node2D::_set_rotd); + + ObjectTypeDB::bind_method(_MD("set_pos","pos"),&Node2D::set_pos); + ObjectTypeDB::bind_method(_MD("set_rot","rot"),&Node2D::set_rot); + ObjectTypeDB::bind_method(_MD("set_scale","scale"),&Node2D::set_scale); + + ObjectTypeDB::bind_method(_MD("get_pos"),&Node2D::get_pos); + ObjectTypeDB::bind_method(_MD("get_rot"),&Node2D::get_rot); + ObjectTypeDB::bind_method(_MD("get_scale"),&Node2D::get_scale); + + ObjectTypeDB::bind_method(_MD("get_global_pos"),&Node2D::get_global_pos); + + ObjectTypeDB::bind_method(_MD("set_transform","xform"),&Node2D::set_transform); + ObjectTypeDB::bind_method(_MD("set_global_transform","xform"),&Node2D::set_global_transform); + + ObjectTypeDB::bind_method(_MD("edit_set_pivot"),&Node2D::edit_set_pivot); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale")); + + + +} + + +Node2D::Node2D() { + + + angle=0; + scale=Vector2(1,1); + _xform_dirty=false; + +} + diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h new file mode 100644 index 0000000000..8da441dc63 --- /dev/null +++ b/scene/2d/node_2d.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* node_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef NODE2D_H +#define NODE2D_H + +#include "scene/2d/canvas_item.h" + +class Node2D : public CanvasItem { + + OBJ_TYPE(Node2D, CanvasItem ); + + Point2 pos; + float angle; + Size2 scale; + + Matrix32 _mat; + + bool _xform_dirty; + + void _update_transform(); + + void _set_rotd(float p_angle); + float _get_rotd() const; + + void _update_xform_values(); + +protected: + + + void _notification(int p_what); + + static void _bind_methods(); +public: + + virtual Variant edit_get_state() const; + virtual void edit_set_state(const Variant& p_state); + virtual void edit_set_rect(const Rect2& p_edit_rect); + virtual void edit_rotate(float p_rot); + virtual void edit_set_pivot(const Point2& p_pivot); + virtual Point2 edit_get_pivot() const; + virtual bool edit_has_pivot() const; + + void set_pos(const Point2& p_pos); + void set_rot(float p_angle); + void set_scale(const Size2& p_scale); + + Point2 get_pos() const; + float get_rot() const; + Size2 get_scale() const; + + Point2 get_global_pos() const; + virtual Rect2 get_item_rect() const; + + void set_transform(const Matrix32& p_transform); + void set_global_transform(const Matrix32& p_transform); + + + Matrix32 get_transform() const; + + Node2D(); +}; + +#endif // NODE2D_H diff --git a/scene/2d/node_2d_singleton.cpp b/scene/2d/node_2d_singleton.cpp new file mode 100644 index 0000000000..58e078101d --- /dev/null +++ b/scene/2d/node_2d_singleton.cpp @@ -0,0 +1,30 @@ +/*************************************************************************/ +/* node_2d_singleton.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "node_2d_singleton.h" + diff --git a/scene/2d/node_2d_singleton.h b/scene/2d/node_2d_singleton.h new file mode 100644 index 0000000000..b1d1e65b8b --- /dev/null +++ b/scene/2d/node_2d_singleton.h @@ -0,0 +1,33 @@ +/*************************************************************************/ +/* node_2d_singleton.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef NODE_2D_SINGLETON_H +#define NODE_2D_SINGLETON_H + + +#endif // NODE_2D_SINGLETON_H diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp new file mode 100644 index 0000000000..55607bd4eb --- /dev/null +++ b/scene/2d/parallax_background.cpp @@ -0,0 +1,200 @@ +/*************************************************************************/ +/* parallax_background.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "parallax_background.h" +#include "parallax_layer.h" + + + +void ParallaxBackground::_notification(int p_what) { + + switch(p_what) { + + + case NOTIFICATION_ENTER_SCENE: { + + group_name = "__cameras_"+itos(get_viewport().get_id()); + add_to_group(group_name); + + } break; + case NOTIFICATION_EXIT_SCENE: { + + remove_from_group(group_name); + } break; + } + +} + +void ParallaxBackground::_camera_moved(const Matrix32& p_transform) { + + + set_scroll_offset(p_transform.get_origin()); + set_scroll_scale(p_transform.get_scale().dot(Vector2(0.5,0.5))); +} + + +void ParallaxBackground::set_scroll_scale(float p_scale) { + + scale=p_scale; +} + +float ParallaxBackground::get_scroll_scale() const{ + + return scale; +} + + +void ParallaxBackground::set_scroll_offset(const Point2& p_ofs) { + + offset=p_ofs; + + _update_scroll(); +} + +void ParallaxBackground::_update_scroll() { + + if (!is_inside_scene()) + return; + + Vector2 ofs = base_offset+offset*base_scale; + + Size2 vps = get_viewport_size(); + + ofs = -ofs; + if (limit_begin.x < limit_end.x) { + + if (ofs.x < limit_begin.x) + ofs.x=limit_begin.x; + else if (ofs.x+vps.x > limit_end.x) + ofs.x=limit_end.x-vps.x; + } + + + if (limit_begin.y < limit_end.y) { + + if (ofs.y < limit_begin.y) + ofs.y=limit_begin.y; + else if (ofs.y+vps.y > limit_end.y) + ofs.y=limit_end.y-vps.y; + } + ofs = -ofs; + + for(int i=0;i<get_child_count();i++) { + + ParallaxLayer *l=get_child(i)->cast_to<ParallaxLayer>(); + if (!l) + continue; + + l->set_base_offset_and_scale(ofs,scale); + } +} + +Point2 ParallaxBackground::get_scroll_offset() const { + + return offset; +} + +void ParallaxBackground::set_scroll_base_offset(const Point2& p_ofs) { + + base_offset=p_ofs; + _update_scroll(); +} + +Point2 ParallaxBackground::get_scroll_base_offset() const{ + + return base_offset; +} + +void ParallaxBackground::set_scroll_base_scale(const Point2& p_ofs) { + + base_scale=p_ofs; + _update_scroll(); +} + +Point2 ParallaxBackground::get_scroll_base_scale() const{ + + return base_scale; +} + + +void ParallaxBackground::set_limit_begin(const Point2& p_ofs) { + + limit_begin=p_ofs; + _update_scroll(); +} + +Point2 ParallaxBackground::get_limit_begin() const { + + return limit_begin; +} + +void ParallaxBackground::set_limit_end(const Point2& p_ofs) { + + limit_end=p_ofs; + _update_scroll(); + +} + +Point2 ParallaxBackground::get_limit_end() const { + + return limit_end; +} + +void ParallaxBackground::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_camera_moved"),&ParallaxBackground::_camera_moved); + ObjectTypeDB::bind_method(_MD("set_scroll_offset","ofs"),&ParallaxBackground::set_scroll_offset); + ObjectTypeDB::bind_method(_MD("get_scroll_offset"),&ParallaxBackground::get_scroll_offset); + ObjectTypeDB::bind_method(_MD("set_scroll_base_offset","ofs"),&ParallaxBackground::set_scroll_base_offset); + ObjectTypeDB::bind_method(_MD("get_scroll_base_offset"),&ParallaxBackground::get_scroll_base_offset); + ObjectTypeDB::bind_method(_MD("set_scroll_base_scale","scale"),&ParallaxBackground::set_scroll_base_scale); + ObjectTypeDB::bind_method(_MD("get_scroll_base_scale"),&ParallaxBackground::get_scroll_base_scale); + ObjectTypeDB::bind_method(_MD("set_limit_begin","ofs"),&ParallaxBackground::set_limit_begin); + ObjectTypeDB::bind_method(_MD("get_limit_begin"),&ParallaxBackground::get_limit_begin); + ObjectTypeDB::bind_method(_MD("set_limit_end","ofs"),&ParallaxBackground::set_limit_end); + ObjectTypeDB::bind_method(_MD("get_limit_end"),&ParallaxBackground::get_limit_end); + + + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/offset"),_SCS("set_scroll_offset"),_SCS("get_scroll_offset")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_offset"),_SCS("set_scroll_base_offset"),_SCS("get_scroll_base_offset")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_scale"),_SCS("set_scroll_base_scale"),_SCS("get_scroll_base_scale")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_begin"),_SCS("set_limit_begin"),_SCS("get_limit_begin")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_end"),_SCS("set_limit_end"),_SCS("get_limit_end")); + +} + + + + + +ParallaxBackground::ParallaxBackground() { + + base_scale=Vector2(1,1); + scale=1.0; + set_layer(-1); //behind all by default +} diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h new file mode 100644 index 0000000000..ed6747f01c --- /dev/null +++ b/scene/2d/parallax_background.h @@ -0,0 +1,78 @@ +/*************************************************************************/ +/* parallax_background.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PARALLAX_BACKGROUND_H +#define PARALLAX_BACKGROUND_H + +#include "scene/main/canvas_layer.h" +#include "scene/2d/node_2d.h" +#include "scene/2d/camera_2d.h" + +class ParallaxBackground : public CanvasLayer { + + OBJ_TYPE( ParallaxBackground, CanvasLayer ); + + Point2 offset; + float scale; + Point2 base_offset; + Point2 base_scale; + String group_name; + Point2 limit_begin; + Point2 limit_end; + + void _update_scroll(); +protected: + + void _camera_moved(const Matrix32& p_transform); + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_scroll_offset(const Point2& p_ofs); + Point2 get_scroll_offset() const; + + void set_scroll_scale(float p_ofs); + float get_scroll_scale() const; + + void set_scroll_base_offset(const Point2& p_ofs); + Point2 get_scroll_base_offset() const; + + void set_scroll_base_scale(const Point2& p_ofs); + Point2 get_scroll_base_scale() const; + + void set_limit_begin(const Point2& p_ofs); + Point2 get_limit_begin() const; + + void set_limit_end(const Point2& p_ofs); + Point2 get_limit_end() const; + + ParallaxBackground(); +}; + +#endif // PARALLAX_BACKGROUND_H diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp new file mode 100644 index 0000000000..2cda51dccb --- /dev/null +++ b/scene/2d/parallax_layer.cpp @@ -0,0 +1,138 @@ +/*************************************************************************/ +/* parallax_layer.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "parallax_layer.h" +#include "parallax_background.h" + +void ParallaxLayer::set_motion_scale(const Size2& p_scale) { + + motion_scale=p_scale; +} + +Size2 ParallaxLayer::get_motion_scale() const { + + return motion_scale; + +} + + +void ParallaxLayer::_update_mirroring() { + + if (!get_parent()) + return; + + ParallaxBackground *pb = get_parent()->cast_to<ParallaxBackground>(); + if (pb) { + + RID c = pb->get_world_2d()->get_canvas(); + RID ci = get_canvas_item(); + VisualServer::get_singleton()->canvas_set_item_mirroring(c,ci,mirroring); + } + +} + +void ParallaxLayer::set_mirroring(const Size2& p_mirroring) { + + mirroring=p_mirroring; + _update_mirroring(); + +} + +Size2 ParallaxLayer::get_mirroring() const{ + + return mirroring; +} + + + +void ParallaxLayer::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + orig_offset=get_pos(); + orig_scale=get_scale(); + _update_mirroring(); + } break; + } +} + +void ParallaxLayer::set_base_offset_and_scale(const Point2& p_offset,float p_scale) { + + if (!is_inside_scene()) + return; + if (get_scene()->is_editor_hint()) + return; + Point2 new_ofs = ((orig_offset+p_offset)*motion_scale)*p_scale; + + if (mirroring.x) { + + while( new_ofs.x>=0) { + new_ofs.x -= mirroring.x*p_scale; + } + while(new_ofs.x < -mirroring.x*p_scale) { + new_ofs.x += mirroring.x*p_scale; + } + } + + if (mirroring.y) { + + while( new_ofs.y>=0) { + new_ofs.y -= mirroring.y*p_scale; + } + while(new_ofs.y < -mirroring.y*p_scale) { + new_ofs.y += mirroring.y*p_scale; + } + } + + + set_pos(new_ofs); + set_scale(Vector2(1,1)*p_scale); + + +} + +void ParallaxLayer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_motion_scale","scale"),&ParallaxLayer::set_motion_scale); + ObjectTypeDB::bind_method(_MD("get_motion_scale"),&ParallaxLayer::get_motion_scale); + ObjectTypeDB::bind_method(_MD("set_mirroring","mirror"),&ParallaxLayer::set_mirroring); + ObjectTypeDB::bind_method(_MD("get_mirroring"),&ParallaxLayer::get_mirroring); + + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"motion/scale"),_SCS("set_motion_scale"),_SCS("get_motion_scale")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"motion/mirroring"),_SCS("set_mirroring"),_SCS("get_mirroring")); + +} + + + +ParallaxLayer::ParallaxLayer() +{ + motion_scale=Size2(1,1); +} diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h new file mode 100644 index 0000000000..fccd8509b1 --- /dev/null +++ b/scene/2d/parallax_layer.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* parallax_layer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PARALLAX_LAYER_H +#define PARALLAX_LAYER_H + +#include "scene/2d/node_2d.h" + +class ParallaxLayer : public Node2D { + + OBJ_TYPE( ParallaxLayer, Node2D ); + + Point2 orig_offset; + Point2 orig_scale; + Size2 motion_scale; + Vector2 mirroring; + void _update_mirroring(); + +protected: + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_motion_scale(const Size2& p_scale); + Size2 get_motion_scale() const; + + void set_mirroring(const Size2& p_mirroring); + Size2 get_mirroring() const; + + void set_base_offset_and_scale(const Point2& p_offsetf,float p_scale); + + ParallaxLayer(); +}; + +#endif // PARALLAX_LAYER_H diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp new file mode 100644 index 0000000000..c10f60f78b --- /dev/null +++ b/scene/2d/particles_2d.cpp @@ -0,0 +1,1045 @@ +/*************************************************************************/ +/* particles_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "particles_2d.h" + + + +void ParticleAttractor2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + _update_owner(); + + } break; + case NOTIFICATION_DRAW: { + + if (!get_scene()->is_editor_hint()) + return; + + Vector2 pv; + float dr = MIN(disable_radius,radius); + for(int i=0;i<=32;i++) { + Vector2 v(Math::sin(i/32.0*Math_PI*2),Math::cos(i/32.0*Math_PI*2)); + if (i>0) { + draw_line(pv*radius,v*radius,Color(0,0,0.5,0.9)); + if (dr>0) { + draw_line(pv*dr,v*dr,Color(0.5,0,0.0,0.9)); + } + } + pv=v; + } + + } break; + case NOTIFICATION_EXIT_SCENE: { + if (owner) { + _set_owner(NULL); + } + + } break; + } +} + +void ParticleAttractor2D::_owner_exited() { + + ERR_FAIL_COND(!owner); + owner->attractors.erase(this); + owner=NULL; +} + +void ParticleAttractor2D::_update_owner() { + + if (!is_inside_scene() || !has_node(path)) { + _set_owner(NULL); + return; + } + + Node *n = get_node(path); + ERR_FAIL_COND(!n); + Particles2D *pn = n->cast_to<Particles2D>(); + if (!pn) { + _set_owner(NULL); + return; + } + + _set_owner(pn); +} + +void ParticleAttractor2D::_set_owner(Particles2D* p_owner) { + + if (owner==p_owner) + return; + + if (owner) { + owner->disconnect("exit_scene",this,"_owner_exited"); + owner->attractors.erase(this); + owner=NULL; + } + owner=p_owner; + + if (owner) { + + owner->connect("exit_scene",this,"_owner_exited",varray(),CONNECT_ONESHOT); + owner->attractors.insert(this); + } +} + +void ParticleAttractor2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&ParticleAttractor2D::set_enabled); + ObjectTypeDB::bind_method(_MD("is_enabled"),&ParticleAttractor2D::is_enabled); + + ObjectTypeDB::bind_method(_MD("set_radius","radius"),&ParticleAttractor2D::set_radius); + ObjectTypeDB::bind_method(_MD("get_radius"),&ParticleAttractor2D::get_radius); + + ObjectTypeDB::bind_method(_MD("set_disable_radius","radius"),&ParticleAttractor2D::set_disable_radius); + ObjectTypeDB::bind_method(_MD("get_disable_radius"),&ParticleAttractor2D::get_disable_radius); + + ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&ParticleAttractor2D::set_gravity); + ObjectTypeDB::bind_method(_MD("get_gravity"),&ParticleAttractor2D::get_gravity); + + ObjectTypeDB::bind_method(_MD("set_absorption","absorption"),&ParticleAttractor2D::set_absorption); + ObjectTypeDB::bind_method(_MD("get_absorption"),&ParticleAttractor2D::get_absorption); + + ObjectTypeDB::bind_method(_MD("set_particles_path","path"),&ParticleAttractor2D::set_particles_path); + ObjectTypeDB::bind_method(_MD("get_particles_path"),&ParticleAttractor2D::get_particles_path); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.1,16000,0.1"),_SCS("set_radius"),_SCS("get_radius")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"disable_radius",PROPERTY_HINT_RANGE,"0.1,16000,0.1"),_SCS("set_disable_radius"),_SCS("get_disable_radius")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-512,512,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"absorption",PROPERTY_HINT_RANGE,"0,512,0.01"),_SCS("set_absorption"),_SCS("get_absorption")); + ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH,"particles_path",PROPERTY_HINT_RESOURCE_TYPE,"Particles2D"),_SCS("set_particles_path"),_SCS("get_particles_path")); + + + +} + + +void ParticleAttractor2D::set_enabled(bool p_enabled) { + + enabled=p_enabled; +} + +bool ParticleAttractor2D::is_enabled() const{ + + return enabled; +} + +void ParticleAttractor2D::set_radius(float p_radius) { + + radius = p_radius; + update(); +} + +float ParticleAttractor2D::get_radius() const { + + return radius; +} + +void ParticleAttractor2D::set_disable_radius(float p_disable_radius) { + + disable_radius = p_disable_radius; + update(); +} +float ParticleAttractor2D::get_disable_radius() const { + + return disable_radius; +} + +void ParticleAttractor2D::set_gravity(float p_gravity) { + + gravity=p_gravity; + +} +float ParticleAttractor2D::get_gravity() const { + + return gravity; +} + +void ParticleAttractor2D::set_absorption(float p_absorption) { + + absorption=p_absorption; + +} +float ParticleAttractor2D::get_absorption() const { + + return absorption; +} + +void ParticleAttractor2D::set_particles_path(NodePath p_path) { + + path=p_path; + _update_owner(); +} +NodePath ParticleAttractor2D::get_particles_path() const { + + return path; +} + + + +ParticleAttractor2D::ParticleAttractor2D() { + + owner=NULL; + radius=50; + disable_radius=0; + gravity=100; + absorption=0; + path=String(".."); + enabled=true; +} + +/****************************************/ + +_FORCE_INLINE_ static float _rand_from_seed(uint32_t *seed) { + + uint32_t k; + uint32_t s = (*seed); + if (s == 0) + s = 0x12345987; + k = s / 127773; + s = 16807 * (s - k * 127773) - 2836 * k; + if (s < 0) + s += 2147483647; + (*seed) = s; + + float v=((float)((*seed) & 0xFFFFF))/(float)0xFFFFF; + v=v*2.0-1.0; + return v; +} + +void Particles2D::_process_particles(float p_delta) { + + if (particles.size()==0 || lifetime==0) + return; + + p_delta*=time_scale; + + float frame_time=p_delta; + + if (emit_timeout > 0) { + time_to_live -= frame_time; + if (time_to_live < 0) { + + emitting = false; + }; + }; + + float next_time = time+frame_time; + + if (next_time > lifetime) + next_time=Math::fmod(next_time,lifetime); + + + Particle *pdata=&particles[0]; + int particle_count=particles.size(); + Matrix32 xform; + if (!local_space) + xform=get_global_transform(); + + active_count=0; + + DVector<Point2>::Read r; + int emission_point_count=0; + if (emission_points.size()) { + + emission_point_count=emission_points.size(); + r=emission_points.read(); + } + + int attractor_count=0; + AttractorCache *attractor_ptr=NULL; + + if (attractors.size()) { + if (attractors.size()!=attractor_cache.size()) { + attractor_cache.resize(attractors.size()); + } + + int idx=0; + Matrix32 m; + if (local_space) { + m= get_global_transform().affine_inverse(); + } + for (Set<ParticleAttractor2D*>::Element *E=attractors.front();E;E=E->next()) { + + attractor_cache[idx].pos=m.xform( E->get()->get_global_pos() ); + attractor_cache[idx].attractor=E->get(); + idx++; + } + + attractor_ptr=attractor_cache.ptr(); + attractor_count=attractor_cache.size(); + } + + for(int i=0;i<particle_count;i++) { + + Particle &p=pdata[i]; + + float restart_time = (i * lifetime / particle_count) * explosiveness; + + bool restart=false; + + if ( next_time < time ) { + + if (restart_time > time || restart_time < next_time ) + restart=true; + + } else if (restart_time > time && restart_time < next_time ) { + restart=true; + } + + if (restart) { + + + if (emitting) { + + p.pos=emissor_offset; + if (emission_point_count) { + + + Vector2 ep = r[Math::rand()%emission_point_count]; + if (!local_space) { + p.pos=xform.xform(p.pos+ep*extents); + } else { + p.pos+=ep*extents; + } + } else { + if (!local_space) { + p.pos=xform.xform(p.pos+Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y))); + } else { + p.pos+=Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y)); + } + } + p.seed=Math::rand() % 12345678; + uint32_t rand_seed=p.seed*(i+1); + + float angle = Math::deg2rad(param[PARAM_DIRECTION]+_rand_from_seed(&rand_seed)*param[PARAM_SPREAD]); + + p.velocity=Vector2( Math::sin(angle), Math::cos(angle) ); + if (!local_space) { + + p.velocity = xform.basis_xform(p.velocity).normalized(); + } + + p.velocity*=param[PARAM_LINEAR_VELOCITY]+param[PARAM_LINEAR_VELOCITY]*_rand_from_seed(&rand_seed)*randomness[PARAM_LINEAR_VELOCITY]; + p.velocity+=initial_velocity; + p.active=true; + p.rot=0; + active_count++; + + + } else { + + p.active=false; + } + + } else { + + if (!p.active) + continue; + + uint32_t rand_seed=p.seed*(i+1); + + Vector2 force; + + //apply gravity + float gravity_dir = Math::deg2rad( param[PARAM_GRAVITY_DIRECTION]+180*randomness[PARAM_GRAVITY_DIRECTION]*_rand_from_seed(&rand_seed)); + force+=Vector2( Math::sin(gravity_dir), Math::cos(gravity_dir) ) * (param[PARAM_GRAVITY_STRENGTH]+param[PARAM_GRAVITY_STRENGTH]*randomness[PARAM_GRAVITY_STRENGTH]*_rand_from_seed(&rand_seed)); + //apply radial + Vector2 rvec = (p.pos - emissor_offset).normalized(); + force+=rvec*(param[PARAM_RADIAL_ACCEL]+param[PARAM_RADIAL_ACCEL]*randomness[PARAM_RADIAL_ACCEL]*_rand_from_seed(&rand_seed)); + //apply orbit + float orbitvel = (param[PARAM_ORBIT_VELOCITY]+param[PARAM_ORBIT_VELOCITY]*randomness[PARAM_ORBIT_VELOCITY]*_rand_from_seed(&rand_seed)); + if (orbitvel!=0) { + Vector2 rel = p.pos - xform.elements[2]; + Matrix32 rot(orbitvel*frame_time,Vector2()); + p.pos = rot.xform(rel) + xform.elements[2]; + + } + + Vector2 tvec=rvec.tangent(); + force+=tvec*(param[PARAM_TANGENTIAL_ACCEL]+param[PARAM_TANGENTIAL_ACCEL]*randomness[PARAM_TANGENTIAL_ACCEL]*_rand_from_seed(&rand_seed)); + + for(int j=0;j<attractor_count;j++) { + + Vector2 vec = (attractor_ptr[j].pos - p.pos); + float vl = vec.length(); + + if (!attractor_ptr[j].attractor->enabled || vl==0 || vl > attractor_ptr[j].attractor->radius) + continue; + + + + force+=vec*attractor_ptr[j].attractor->gravity; + float fvl = p.velocity.length(); + if (fvl && attractor_ptr[j].attractor->absorption) { + Vector2 target = vec.normalized(); + p.velocity = p.velocity.normalized().linear_interpolate(target,MIN(frame_time*attractor_ptr[j].attractor->absorption,1))*fvl; + } + + if (attractor_ptr[j].attractor->disable_radius && vl < attractor_ptr[j].attractor->disable_radius) { + p.active=false; + } + } + + p.velocity+=force*frame_time; + + if (param[PARAM_DAMPING]) { + float dmp = param[PARAM_DAMPING]+param[PARAM_DAMPING]*randomness[PARAM_DAMPING]*_rand_from_seed(&rand_seed); + float v = p.velocity.length(); + v -= dmp * frame_time; + if (v<=0) { + p.velocity=Vector2(); + } else { + p.velocity=p.velocity.normalized() * v; + } + + } + + p.pos+=p.velocity*frame_time; + p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time; + + active_count++; + + } + + + } + + + + time=Math::fmod( time+frame_time, lifetime ); + if (!emitting && active_count==0) { + set_process(false); + + } + + update(); + + +} + + +void Particles2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_PROCESS: { + + _process_particles( get_process_delta_time() ); + } break; + + case NOTIFICATION_ENTER_SCENE: { + + float ppt=preprocess; + while(ppt>0) { + _process_particles(0.1); + ppt-=0.1; + } + } break; + case NOTIFICATION_DRAW: { + + + if (particles.size()==0 || lifetime==0) + return; + + RID ci=get_canvas_item(); + Size2 size(1,1); + Point2 center; + + if (!texture.is_null()) { + size=texture->get_size(); + } + + + float time_pos=(time/lifetime); + + Particle *pdata=&particles[0]; + int particle_count=particles.size(); + Rect2 r(Point2(),size); + RID texrid; + + if (texture.is_valid()) + texrid = texture->get_rid(); + + Matrix32 invxform; + if (!local_space) + invxform=get_global_transform().affine_inverse(); + + int col_count=0; + float last=-1; + ColorPhase cphase[MAX_COLOR_PHASES]; + + for(int i=0;i<color_phase_count;i++) { + + if (color_phases[i].pos<=last) + break; + cphase[i]=color_phases[i]; + col_count++; + } + + + for(int i=0;i<particle_count;i++) { + + Particle &p=pdata[i]; + if (!p.active) + continue; + + float ptime = ((float)i / particle_count)*explosiveness; + + if (ptime<time_pos) + ptime=time_pos-ptime; + else + ptime=(1.0-ptime)+time_pos; + + uint32_t rand_seed=p.seed*(i+1); + + + int cpos=0; + + while(cpos<col_count) { + + if (cphase[cpos].pos > ptime) + break; + cpos++; + } + + cpos--; + + Color color; + //could be faster.. + if (cpos==-1) + color=Color(1,1,1,1); + else { + if (cpos==col_count-1) + color=cphase[cpos].color; + else { + float diff = (cphase[cpos+1].pos-cphase[cpos].pos); + if (diff>0) + color=cphase[cpos].color.linear_interpolate(cphase[cpos+1].color, (ptime - cphase[cpos].pos) / diff ); + else + color=cphase[cpos+1].color; + } + } + + + { + float huerand=_rand_from_seed(&rand_seed); + float huerot = param[PARAM_HUE_VARIATION] + randomness[PARAM_HUE_VARIATION] * huerand; + + if (Math::abs(huerot) > CMP_EPSILON) { + + float h=color.get_h(); + float s=color.get_s(); + float v=color.get_v(); + float a=color.a; + //float preh=h; + h+=huerot; + h=Math::abs(Math::fposmod(h,1.0)); + //print_line("rand: "+rtos(randomness[PARAM_HUE_VARIATION])+" rand: "+rtos(huerand)); + //print_line(itos(i)+":hue: "+rtos(preh)+" + "+rtos(huerot)+" = "+rtos(h)); + color.set_hsv(h,s,v); + color.a=a; + } + } + + float initial_size = param[PARAM_INITIAL_SIZE]+param[PARAM_INITIAL_SIZE]*_rand_from_seed(&rand_seed)*randomness[PARAM_FINAL_SIZE]; + float final_size = param[PARAM_FINAL_SIZE]+param[PARAM_FINAL_SIZE]*_rand_from_seed(&rand_seed)*randomness[PARAM_FINAL_SIZE]; + + float size_mult=initial_size*(1.0-ptime) + final_size*ptime; + + //Size2 rectsize=size * size_mult; + //rectsize=rectsize.floor(); + + //Rect2 r = Rect2(Vecto,rectsize); + + Matrix32 xform; + + if (p.rot) { + + xform.set_rotation(p.rot); + xform.translate(-size*size_mult/2.0); + xform.elements[2]+=p.pos; + } else { + xform.elements[2]=-size*size_mult/2.0; + xform.elements[2]+=p.pos; + } + + if (!local_space) { + xform = invxform * xform; + } + + + xform.scale_basis(Size2(size_mult,size_mult)); + + + VisualServer::get_singleton()->canvas_item_add_set_transform(ci,xform); + + + if (texrid.is_valid()) { + + VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color); + } else { + VisualServer::get_singleton()->canvas_item_add_rect(ci,r,color); + + } + + } + + + } break; + + } + +} + +static const char* _particlesframe_property_names[Particles2D::PARAM_MAX]={ + "params/direction", + "params/spread", + "params/linear_velocity", + "params/spin_velocity", + "params/orbit_velocity", + "params/gravity_direction", + "params/gravity_strength", + "params/radial_accel", + "params/tangential_accel", + "params/damping", + "params/initial_size", + "params/final_size", + "params/hue_variation" +}; + +static const char* _particlesframe_property_rnames[Particles2D::PARAM_MAX]={ + "randomness/direction", + "randomness/spread", + "randomness/linear_velocity", + "randomness/spin_velocity", + "randomness/orbit_velocity", + "randomness/gravity_direction", + "randomness/gravity_strength", + "randomness/radial_accel", + "randomness/tangential_accel", + "randomness/damping", + "randomness/initial_size", + "randomness/final_size", + "randomness/hue_variation" +}; + +static const char* _particlesframe_property_ranges[Particles2D::PARAM_MAX]={ + "0,360,0.01", + "0,180,0.01", + "-1024,1024,0.01", + "-1024,1024,0.01", + "-1024,1024,0.01", + "0,360,0.01", + "0,1024,0.01", + "-128,128,0.01", + "-128,128,0.01", + "0,1024,0.001", + "0,1024,0.01", + "0,1024,0.01", + "0,1,0.01" +}; + + +void Particles2D::set_emitting(bool p_emitting) { + + if (emitting==p_emitting) + return; + + if (p_emitting) { + + if (active_count==0) + time=0; + set_process(true); + time_to_live = emit_timeout; + }; + emitting=p_emitting; +} + +bool Particles2D::is_emitting() const { + + return emitting; +} + +void Particles2D::set_amount(int p_amount) { + + ERR_FAIL_INDEX(p_amount,1024); + + particles.resize(p_amount); +} +int Particles2D::get_amount() const { + + return particles.size(); +} + +void Particles2D::set_emit_timeout(float p_timeout) { + + emit_timeout = p_timeout; + time_to_live = p_timeout; +}; + +float Particles2D::get_emit_timeout() const { + + return emit_timeout; +}; + +void Particles2D::set_lifetime(float p_lifetime) { + + ERR_FAIL_INDEX(p_lifetime,3600); + + lifetime=p_lifetime; +} +float Particles2D::get_lifetime() const { + + return lifetime; +} + +void Particles2D::set_time_scale(float p_time_scale) { + + time_scale=p_time_scale; +} +float Particles2D::get_time_scale() const { + + return time_scale; +} + +void Particles2D::set_pre_process_time(float p_pre_process_time) { + + preprocess=p_pre_process_time; +} + +float Particles2D::get_pre_process_time() const{ + + return preprocess; +} + + +void Particles2D::set_param(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param,PARAM_MAX); + param[p_param]=p_value; +} +float Particles2D::get_param(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0); + return param[p_param]; +} + +void Particles2D::set_randomness(Parameter p_param, float p_value) { + + ERR_FAIL_INDEX(p_param,PARAM_MAX); + randomness[p_param]=p_value; + +} +float Particles2D::get_randomness(Parameter p_param) const { + + ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0); + return randomness[p_param]; + +} + +void Particles2D::set_texture(const Ref<Texture>& p_texture) { + + texture=p_texture; +} + +Ref<Texture> Particles2D::get_texture() const { + + return texture; +} + +void Particles2D::set_emissor_offset(const Point2& p_offset) { + + emissor_offset=p_offset; +} + +Point2 Particles2D::get_emissor_offset() const { + + return emissor_offset; +} + + +void Particles2D::set_use_local_space(bool p_use) { + + local_space=p_use; +} + +bool Particles2D::is_using_local_space() const { + + return local_space; +} + + +void Particles2D::set_color_phases(int p_phases) { + + ERR_FAIL_INDEX(p_phases,MAX_COLOR_PHASES+1); + color_phase_count=p_phases; +} + +int Particles2D::get_color_phases() const { + + return color_phase_count; +} + +void Particles2D::set_color_phase_color(int p_phase,const Color& p_color) { + + ERR_FAIL_INDEX(p_phase,MAX_COLOR_PHASES); + color_phases[p_phase].color=p_color; + +} +Color Particles2D::get_color_phase_color(int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase,MAX_COLOR_PHASES,Color()); + return color_phases[p_phase].color; +} + +void Particles2D::set_color_phase_pos(int p_phase,float p_pos) { + ERR_FAIL_INDEX(p_phase,MAX_COLOR_PHASES); + ERR_FAIL_COND(p_pos<0.0 || p_pos>1.0); + color_phases[p_phase].pos=p_pos; + +} +float Particles2D::get_color_phase_pos(int p_phase) const { + + ERR_FAIL_INDEX_V(p_phase,MAX_COLOR_PHASES,0); + return color_phases[p_phase].pos; +} + +void Particles2D::set_emission_half_extents(const Vector2& p_extents) { + + extents=p_extents; +} + +Vector2 Particles2D::get_emission_half_extents() const { + + return extents; +} + +void Particles2D::testee(int a, int b, int c, int d, int e) { + + print_line(itos(a)); + print_line(itos(b)); + print_line(itos(c)); + print_line(itos(d)); + print_line(itos(e)); +} + +void Particles2D::set_initial_velocity(const Vector2& p_velocity) { + + + initial_velocity=p_velocity; +} +Vector2 Particles2D::get_initial_velocity() const{ + + return initial_velocity; +} + + +void Particles2D::pre_process(float p_delta) { + + _process_particles(p_delta); +} + + +void Particles2D::set_explosiveness(float p_value) { + + explosiveness=p_value; +} + +float Particles2D::get_explosiveness() const{ + + return explosiveness; +} + +void Particles2D::set_emission_points(const DVector<Vector2>& p_points) { + + emission_points=p_points; +} + +DVector<Vector2> Particles2D::get_emission_points() const{ + + return emission_points; +} + +void Particles2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_emitting","active"),&Particles2D::set_emitting); + ObjectTypeDB::bind_method(_MD("is_emitting"),&Particles2D::is_emitting); + + ObjectTypeDB::bind_method(_MD("set_amount","amount"),&Particles2D::set_amount); + ObjectTypeDB::bind_method(_MD("get_amount"),&Particles2D::get_amount); + + ObjectTypeDB::bind_method(_MD("set_lifetime","lifetime"),&Particles2D::set_lifetime); + ObjectTypeDB::bind_method(_MD("get_lifetime"),&Particles2D::get_lifetime); + + ObjectTypeDB::bind_method(_MD("set_time_scale","time_scale"),&Particles2D::set_time_scale); + ObjectTypeDB::bind_method(_MD("get_time_scale"),&Particles2D::get_time_scale); + + ObjectTypeDB::bind_method(_MD("set_pre_process_time","time"),&Particles2D::set_pre_process_time); + ObjectTypeDB::bind_method(_MD("get_pre_process_time"),&Particles2D::get_pre_process_time); + + ObjectTypeDB::bind_method(_MD("set_emit_timeout","value"),&Particles2D::set_emit_timeout); + ObjectTypeDB::bind_method(_MD("get_emit_timeout"),&Particles2D::get_emit_timeout); + + ObjectTypeDB::bind_method(_MD("set_param","param","value"),&Particles2D::set_param); + ObjectTypeDB::bind_method(_MD("get_param","param"),&Particles2D::get_param); + + ObjectTypeDB::bind_method(_MD("set_randomness","param","value"),&Particles2D::set_randomness); + ObjectTypeDB::bind_method(_MD("get_randomness","param"),&Particles2D::get_randomness); + + ObjectTypeDB::bind_method(_MD("set_texture:Texture","texture"),&Particles2D::set_texture); + ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&Particles2D::get_texture); + + ObjectTypeDB::bind_method(_MD("set_emissor_offset","offset"),&Particles2D::set_emissor_offset); + ObjectTypeDB::bind_method(_MD("get_emissor_offset"),&Particles2D::get_emissor_offset); + + ObjectTypeDB::bind_method(_MD("set_emission_half_extents","extents"),&Particles2D::set_emission_half_extents); + ObjectTypeDB::bind_method(_MD("get_emission_half_extents"),&Particles2D::get_emission_half_extents); + + ObjectTypeDB::bind_method(_MD("set_color_phases","phases"),&Particles2D::set_color_phases); + ObjectTypeDB::bind_method(_MD("get_color_phases"),&Particles2D::get_color_phases); + + ObjectTypeDB::bind_method(_MD("set_color_phase_color","phase","color"),&Particles2D::set_color_phase_color); + ObjectTypeDB::bind_method(_MD("get_color_phase_color","phase"),&Particles2D::get_color_phase_color); + + ObjectTypeDB::bind_method(_MD("set_color_phase_pos","phase","pos"),&Particles2D::set_color_phase_pos); + ObjectTypeDB::bind_method(_MD("get_color_phase_pos","phase"),&Particles2D::get_color_phase_pos); + + ObjectTypeDB::bind_method(_MD("pre_process","time"),&Particles2D::pre_process); + + ObjectTypeDB::bind_method(_MD("set_use_local_space","enable"),&Particles2D::set_use_local_space); + ObjectTypeDB::bind_method(_MD("is_using_local_space"),&Particles2D::is_using_local_space); + + ObjectTypeDB::bind_method(_MD("set_initial_velocity","velocity"),&Particles2D::set_initial_velocity); + ObjectTypeDB::bind_method(_MD("get_initial_velocity"),&Particles2D::get_initial_velocity); + + ObjectTypeDB::bind_method(_MD("set_explosiveness","amount"),&Particles2D::set_explosiveness); + ObjectTypeDB::bind_method(_MD("get_explosiveness"),&Particles2D::get_explosiveness); + + ObjectTypeDB::bind_method(_MD("set_emission_points","points"),&Particles2D::set_emission_points); + ObjectTypeDB::bind_method(_MD("get_emission_points"),&Particles2D::get_emission_points); + + ADD_PROPERTY(PropertyInfo(Variant::INT,"config/amount",PROPERTY_HINT_EXP_RANGE,"1,1024"),_SCS("set_amount"),_SCS("get_amount") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/lifetime",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_lifetime"),_SCS("get_lifetime") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") ); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") ); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") ); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness")); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); + + + for(int i=0;i<PARAM_MAX;i++) { + ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_names[i],PROPERTY_HINT_RANGE,_particlesframe_property_ranges[i]),_SCS("set_param"),_SCS("get_param"),i); + } + + for(int i=0;i<PARAM_MAX;i++) { + ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i); + } + + ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1"), _SCS("set_color_phases"), _SCS("get_color_phases")); + + for(int i=0;i<MAX_COLOR_PHASES;i++) { + String phase="phase_"+itos(i)+"/"; + ADD_PROPERTYI( PropertyInfo( Variant::REAL, phase+"pos", PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_color_phase_pos"),_SCS("get_color_phase_pos"),i ); + ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color"),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i ); + } + + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points")); + + BIND_CONSTANT( PARAM_DIRECTION ); + BIND_CONSTANT( PARAM_SPREAD ); + BIND_CONSTANT( PARAM_LINEAR_VELOCITY ); + BIND_CONSTANT( PARAM_SPIN_VELOCITY ); + BIND_CONSTANT( PARAM_GRAVITY_DIRECTION ); + BIND_CONSTANT( PARAM_GRAVITY_STRENGTH ); + BIND_CONSTANT( PARAM_RADIAL_ACCEL ); + BIND_CONSTANT( PARAM_TANGENTIAL_ACCEL ); + BIND_CONSTANT( PARAM_INITIAL_SIZE ); + BIND_CONSTANT( PARAM_FINAL_SIZE ); + BIND_CONSTANT( PARAM_HUE_VARIATION ); + BIND_CONSTANT( PARAM_MAX ); + + BIND_CONSTANT( MAX_COLOR_PHASES ); + +} + + + +Particles2D::Particles2D() { + + for(int i=0;i<PARAM_MAX;i++) { + + param[i]=0; + randomness[i]=0; + } + + + set_param(PARAM_SPREAD,10); + set_param(PARAM_LINEAR_VELOCITY,20); + set_param(PARAM_GRAVITY_STRENGTH,9.8); + set_param(PARAM_RADIAL_ACCEL,0); + set_param(PARAM_TANGENTIAL_ACCEL,0); + set_param(PARAM_INITIAL_SIZE,1.0); + set_param(PARAM_FINAL_SIZE,1.0); + + + time=0; + lifetime=2; + emitting=false; + particles.resize(32); + active_count=-1; + set_emitting(true); + local_space=true; + preprocess=0; + time_scale=1.0; + + color_phase_count=1; + + set_color_phase_pos(0,0.0); + set_color_phase_pos(1,1.0); + set_color_phase_pos(2,1.0); + set_color_phase_pos(3,1.0); + + set_color_phase_color(0,Color(1,1,1)); + set_color_phase_color(1,Color(0,0,0)); + set_color_phase_color(2,Color(0,0,0)); + set_color_phase_color(3,Color(0,0,0)); + + emit_timeout = 0; + time_to_live = 0; + explosiveness=1.0; +} diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h new file mode 100644 index 0000000000..8849149127 --- /dev/null +++ b/scene/2d/particles_2d.h @@ -0,0 +1,231 @@ +/*************************************************************************/ +/* particles_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PARTICLES_FRAME_H +#define PARTICLES_FRAME_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/texture.h" + +class Particles2D; +class ParticleAttractor2D : public Node2D { + + OBJ_TYPE(ParticleAttractor2D,Node2D); + + +friend class Particles2D; + bool enabled; + float radius; + float disable_radius; + float gravity; + float absorption; + NodePath path; + + Particles2D *owner; + + void _update_owner(); + void _owner_exited(); + void _set_owner(Particles2D* p_owner); + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_enabled(bool p_enabled); + bool is_enabled() const; + + void set_radius(float p_radius); + float get_radius() const; + + void set_disable_radius(float p_disable_radius); + float get_disable_radius() const; + + void set_gravity(float p_gravity); + float get_gravity() const; + + void set_absorption(float p_absorption); + float get_absorption() const; + + void set_particles_path(NodePath p_path); + NodePath get_particles_path() const; + + ParticleAttractor2D(); +}; + + + +class Particles2D : public Node2D { + + OBJ_TYPE(Particles2D, Node2D); +public: + + enum Parameter { + PARAM_DIRECTION, + PARAM_SPREAD, + PARAM_LINEAR_VELOCITY, + PARAM_SPIN_VELOCITY, + PARAM_ORBIT_VELOCITY, + PARAM_GRAVITY_DIRECTION, + PARAM_GRAVITY_STRENGTH, + PARAM_RADIAL_ACCEL, + PARAM_TANGENTIAL_ACCEL, + PARAM_DAMPING, + PARAM_INITIAL_SIZE, + PARAM_FINAL_SIZE, + PARAM_HUE_VARIATION, + PARAM_MAX + }; + + enum { + MAX_COLOR_PHASES=4 + }; + +private: + + float param[PARAM_MAX]; + float randomness[PARAM_MAX]; + + struct Particle { + + bool active; + Point2 pos; + Vector2 velocity; + float rot; + uint32_t seed; + Particle() { active=false; seed=123465789; rot=0;} + }; + + Vector<Particle> particles; + int color_phase_count; + struct ColorPhase { + Color color; + float pos; + } color_phases[MAX_COLOR_PHASES]; + + struct AttractorCache { + + Vector2 pos; + ParticleAttractor2D *attractor; + }; + + Vector<AttractorCache> attractor_cache; + + float explosiveness; + float preprocess; + float lifetime; + bool emitting; + bool local_space; + float emit_timeout; + float time_to_live; + float time_scale; + Point2 emissor_offset; + Vector2 initial_velocity; + Vector2 extents; + DVector<Vector2> emission_points; + + float time; + int active_count; + + Ref<Texture> texture; + + + void testee(int a, int b, int c, int d, int e); + void _process_particles(float p_delta); +friend class ParticleAttractor2D; + + Set<ParticleAttractor2D*> attractors; + +protected: + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_emitting(bool p_emitting); + bool is_emitting() const; + + void set_amount(int p_amount); + int get_amount() const; + + void set_lifetime(float p_lifetime); + float get_lifetime() const; + + void set_time_scale(float p_time_scale); + float get_time_scale() const; + + void set_pre_process_time(float p_pre_process_time); + float get_pre_process_time() const; + + void set_emit_timeout(float p_timeout); + float get_emit_timeout() const; + + void set_emission_half_extents(const Vector2& p_extents); + Vector2 get_emission_half_extents() const; + + void set_param(Parameter p_param, float p_value); + float get_param(Parameter p_param) const; + + void set_randomness(Parameter p_randomness, float p_value); + float get_randomness(Parameter p_randomness) const; + + void set_explosiveness(float p_value); + float get_explosiveness() const; + + void set_color_phases(int p_phases); + int get_color_phases() const; + + void set_color_phase_color(int p_phase,const Color& p_color); + Color get_color_phase_color(int p_phase) const; + + void set_color_phase_pos(int p_phase,float p_pos); + float get_color_phase_pos(int p_phase) const; + + void set_texture(const Ref<Texture>& p_texture); + Ref<Texture> get_texture() const; + + void set_emissor_offset(const Point2& p_offset); + Point2 get_emissor_offset() const; + + void set_use_local_space(bool p_use); + bool is_using_local_space() const; + + void set_initial_velocity(const Vector2& p_velocity); + Vector2 get_initial_velocity() const; + + void set_emission_points(const DVector<Vector2>& p_points); + DVector<Vector2> get_emission_points() const; + + void pre_process(float p_delta); + + Particles2D(); +}; + +VARIANT_ENUM_CAST( Particles2D::Parameter ); + +#endif // PARTICLES_FRAME_H diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp new file mode 100644 index 0000000000..22d56609ee --- /dev/null +++ b/scene/2d/path_2d.cpp @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* path_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "path_2d.h" + + +void Path2D::_notification(int p_what) { + + if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) { + //draw the curve!! + + for(int i=0;i<curve->get_point_count();i++) { + + Vector2 prev_p=curve->get_point_pos(i); + + for(int j=1;j<=8;j++) { + + real_t frac = j/8.0; + Vector2 p = curve->interpolate(i,frac); + draw_line(prev_p,p,Color(0.5,0.6,1.0,0.7),2); + prev_p=p; + } + } + } +} + +void Path2D::_curve_changed() { + + + if (is_inside_scene() && get_scene()->is_editor_hint()) + update(); + +} + + +void Path2D::set_curve(const Ref<Curve2D>& p_curve) { + + if (curve.is_valid()) { + curve->disconnect("changed",this,"_curve_changed"); + } + + curve=p_curve; + + if (curve.is_valid()) { + curve->connect("changed",this,"_curve_changed"); + } + +} + +Ref<Curve2D> Path2D::get_curve() const{ + + return curve; +} + +void Path2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve2D"),&Path2D::set_curve); + ObjectTypeDB::bind_method(_MD("get_curve:Curve2D","curve"),&Path2D::get_curve); + ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path2D::_curve_changed); + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve2D"), _SCS("set_curve"),_SCS("get_curve")); +} + +Path2D::Path2D() { + + set_curve(Ref<Curve2D>( memnew( Curve2D ))); //create one by default +} diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h new file mode 100644 index 0000000000..f401f9da4c --- /dev/null +++ b/scene/2d/path_2d.h @@ -0,0 +1,57 @@ +/*************************************************************************/ +/* path_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PATH_2D_H +#define PATH_2D_H + +#include "scene/resources/curve.h" +#include "scene/2d/node_2d.h" + +class Path2D : public Node2D { + + OBJ_TYPE( Path2D, Node2D ); + + Ref<Curve2D> curve; + + void _curve_changed(); + + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_curve(const Ref<Curve2D>& p_curve); + Ref<Curve2D> get_curve() const; + + + Path2D(); +}; + +#endif // PATH_2D_H diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp new file mode 100644 index 0000000000..945e50ff51 --- /dev/null +++ b/scene/2d/physics_body_2d.cpp @@ -0,0 +1,794 @@ +/*************************************************************************/ +/* physics_body_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "physics_body_2d.h" +#include "scene/scene_string_names.h" + +void PhysicsBody2D::_notification(int p_what) { + +/* + switch(p_what) { + + case NOTIFICATION_TRANSFORM_CHANGED: { + + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform()); + + } break; + } + */ +} + +PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) { + + + +} + +void StaticBody2D::set_constant_linear_velocity(const Vector2& p_vel) { + + constant_linear_velocity=p_vel; + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_LINEAR_VELOCITY,constant_linear_velocity); + +} + +void StaticBody2D::set_constant_angular_velocity(real_t p_vel) { + + constant_angular_velocity=p_vel; + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_ANGULAR_VELOCITY,constant_angular_velocity); +} + +Vector2 StaticBody2D::get_constant_linear_velocity() const { + + return constant_linear_velocity; +} +real_t StaticBody2D::get_constant_angular_velocity() const { + + return constant_angular_velocity; +} + + +void StaticBody2D::_state_notify(Object *p_object) { + + if (!pre_xform) + return; + + Physics2DDirectBodyState *p2d = (Physics2DDirectBodyState*)p_object; + setting=true; + + Matrix32 new_xform = p2d->get_transform(); + *pre_xform=new_xform; + set_block_transform_notify(true); + set_global_transform(new_xform); + set_block_transform_notify(false); + + setting=false; + + +} + +void StaticBody2D::_update_xform() { + + if (!pre_xform || !pending) + return; + + setting=true; + + + Matrix32 new_xform = get_global_transform(); //obtain the new one + + set_block_transform_notify(true); + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_TRANSFORM,*pre_xform); //then simulate motion! + set_global_transform(*pre_xform); //but restore state to previous one in both visual and physics + set_block_transform_notify(false); + + Physics2DServer::get_singleton()->body_static_simulate_motion(get_rid(),new_xform); //then simulate motion! + + setting=false; + pending=false; + +} + +void StaticBody2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + if (pre_xform) + *pre_xform = get_global_transform(); + pending=false; + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + if (simulating_motion && !pending && is_inside_scene() && !setting && !get_scene()->is_editor_hint()) { + + + call_deferred(SceneStringNames::get_singleton()->_update_xform); + pending=true; + } + + } break; + } + + +} + +void StaticBody2D::set_simulate_motion(bool p_enable) { + + if (p_enable==simulating_motion) + return; + simulating_motion=p_enable; + + if (p_enable) { + pre_xform = memnew( Matrix32 ); + if (is_inside_scene()) + *pre_xform=get_transform(); +// query = Physics2DServer::get_singleton()->query_create(this,"_state_notify",Variant()); + // Physics2DServer::get_singleton()->query_body_direct_state(query,get_rid()); + Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_state_notify"); + + } else { + memdelete( pre_xform ); + pre_xform=NULL; + Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(),NULL,StringName()); + pending=false; + } +} + +bool StaticBody2D::is_simulating_motion() const { + + return simulating_motion; +} + + +void StaticBody2D::set_friction(real_t p_friction){ + + ERR_FAIL_COND(p_friction<0 || p_friction>1); + + friction=p_friction; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_FRICTION,friction); + +} +real_t StaticBody2D::get_friction() const{ + + return friction; +} + +void StaticBody2D::set_bounce(real_t p_bounce){ + + ERR_FAIL_COND(p_bounce<0 || p_bounce>1); + + bounce=p_bounce; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_BOUNCE,bounce); + +} +real_t StaticBody2D::get_bounce() const{ + + return bounce; +} + +void StaticBody2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_simulate_motion","enabled"),&StaticBody2D::set_simulate_motion); + ObjectTypeDB::bind_method(_MD("is_simulating_motion"),&StaticBody2D::is_simulating_motion); + ObjectTypeDB::bind_method(_MD("_update_xform"),&StaticBody2D::_update_xform); + ObjectTypeDB::bind_method(_MD("_state_notify"),&StaticBody2D::_state_notify); + ObjectTypeDB::bind_method(_MD("set_constant_linear_velocity","vel"),&StaticBody2D::set_constant_linear_velocity); + ObjectTypeDB::bind_method(_MD("set_constant_angular_velocity","vel"),&StaticBody2D::set_constant_angular_velocity); + ObjectTypeDB::bind_method(_MD("get_constant_linear_velocity"),&StaticBody2D::get_constant_linear_velocity); + ObjectTypeDB::bind_method(_MD("get_constant_angular_velocity"),&StaticBody2D::get_constant_angular_velocity); + ObjectTypeDB::bind_method(_MD("set_friction","friction"),&StaticBody2D::set_friction); + ObjectTypeDB::bind_method(_MD("get_friction"),&StaticBody2D::get_friction); + + ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&StaticBody2D::set_bounce); + ObjectTypeDB::bind_method(_MD("get_bounce"),&StaticBody2D::get_bounce); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"simulate_motion"),_SCS("set_simulate_motion"),_SCS("is_simulating_motion")); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"constant_linear_velocity"),_SCS("set_constant_linear_velocity"),_SCS("get_constant_linear_velocity")); + ADD_PROPERTY(PropertyInfo(Variant::REAL,"constant_angular_velocity"),_SCS("set_constant_angular_velocity"),_SCS("get_constant_angular_velocity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce")); +} + +StaticBody2D::StaticBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_STATIC) { + + simulating_motion=false; + pre_xform=NULL; + setting=false; + pending=false; + constant_angular_velocity=0; + bounce=0; + friction=1; + + +} + +StaticBody2D::~StaticBody2D() { + + if (pre_xform) + memdelete(pre_xform); + //if (query.is_valid()) + // Physics2DServer::get_singleton()->free(query); +} + + + + +void RigidBody2D::_body_enter_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->get().in_scene); + + E->get().in_scene=true; + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape); + } + +} + +void RigidBody2D::_body_exit_scene(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->get().in_scene); + E->get().in_scene=false; + emit_signal(SceneStringNames::get_singleton()->body_exit,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,p_id,node,E->get().shapes[i].body_shape,E->get().shapes[i].local_shape); + } +} + +void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape) { + + bool body_in = p_status==1; + ObjectID objid=p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = obj ? obj->cast_to<Node>() : NULL; + + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(objid); + + ERR_FAIL_COND(!body_in && !E); + + if (body_in) { + if (!E) { + + E = contact_monitor->body_map.insert(objid,BodyState()); + E->get().rc=0; + E->get().in_scene=node && node->is_inside_scene(); + if (node) { + node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter,node); + } + } + + } + E->get().rc++; + if (node) + E->get().shapes.insert(ShapePair(p_body_shape,p_local_shape)); + + + if (E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_local_shape); + } + + } else { + + E->get().rc--; + + if (node) + E->get().shapes.erase(ShapePair(p_body_shape,p_local_shape)); + + if (E->get().rc==0) { + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); + node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + if (E->get().in_scene) + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + } + + contact_monitor->body_map.erase(E); + } + if (node && E->get().in_scene) { + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_local_shape); + } + + } + +} + + +struct _RigidBody2DInOut { + + ObjectID id; + int shape; + int local_shape; +}; + +void RigidBody2D::_direct_state_changed(Object *p_state) { + + //eh.. fuck +#ifdef DEBUG_ENABLED + + state=p_state->cast_to<Physics2DDirectBodyState>(); +#else + state=(Physics2DDirectBodyState*)p_state; //trust it +#endif + + if (contact_monitor) { + + //untag all + int rc=0; + for( Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) { + + for(int i=0;i<E->get().shapes.size();i++) { + + E->get().shapes[i].tagged=false; + rc++; + } + } + + _RigidBody2DInOut *toadd=(_RigidBody2DInOut*)alloca(state->get_contact_count()*sizeof(_RigidBody2DInOut)); + int toadd_count=0;//state->get_contact_count(); + RigidBody2D_RemoveAction *toremove=(RigidBody2D_RemoveAction*)alloca(rc*sizeof(RigidBody2D_RemoveAction)); + int toremove_count=0; + + //put the ones to add + + for(int i=0;i<state->get_contact_count();i++) { + + ObjectID obj = state->get_contact_collider_id(i); + int local_shape = state->get_contact_local_shape(i); + int shape = state->get_contact_collider_shape(i); + toadd[i].local_shape=local_shape; + toadd[i].id=obj; + toadd[i].shape=shape; + + bool found=false; + + Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(obj); + if (!E) { + toadd_count++; + continue; + } + + ShapePair sp( shape,local_shape ); + int idx = E->get().shapes.find(sp); + if (idx==-1) { + + toadd_count++; + continue; + } + + E->get().shapes[idx].tagged=true; + } + + //put the ones to remove + + for( Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) { + + for(int i=0;i<E->get().shapes.size();i++) { + + if (!E->get().shapes[i].tagged) { + + toremove[toremove_count].body_id=E->key(); + toremove[toremove_count].pair=E->get().shapes[i]; + toremove_count++; + } + } + } + + + //process remotions + + for(int i=0;i<toremove_count;i++) { + + _body_inout(0,toremove[i].body_id,toremove[i].pair.body_shape,toremove[i].pair.local_shape); + } + + //process aditions + + for(int i=0;i<toadd_count;i++) { + + _body_inout(1,toadd[i].id,toadd[i].shape,toadd[i].local_shape); + } + + } + + set_block_transform_notify(true); // don't want notify (would feedback loop) + set_global_transform(state->get_transform()); + linear_velocity=state->get_linear_velocity(); + angular_velocity=state->get_angular_velocity(); + active=!state->is_sleeping(); + if (get_script_instance()) + get_script_instance()->call("_integrate_forces",state); + set_block_transform_notify(false); // want it back + + state=NULL; +} + +void RigidBody2D::_notification(int p_what) { + + +} + +void RigidBody2D::set_mode(Mode p_mode) { + + mode=p_mode; + switch(p_mode) { + + case MODE_RIGID: { + + Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_RIGID); + } break; + case MODE_STATIC: { + + Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_STATIC); + + } break; + case MODE_STATIC_ACTIVE: { + + Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_STATIC_ACTIVE); + + } break; + case MODE_CHARACTER: { + Physics2DServer::get_singleton()->body_set_mode(get_rid(),Physics2DServer::BODY_MODE_CHARACTER); + + } break; + + } +} + +RigidBody2D::Mode RigidBody2D::get_mode() const{ + + return mode; +} + +void RigidBody2D::set_mass(real_t p_mass){ + + ERR_FAIL_COND(p_mass<=0); + mass=p_mass; + _change_notify("mass"); + _change_notify("weight"); + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_MASS,mass); + +} +real_t RigidBody2D::get_mass() const{ + + return mass; +} + +void RigidBody2D::set_weight(real_t p_weight){ + + set_mass(p_weight/9.8); +} +real_t RigidBody2D::get_weight() const{ + + return mass*9.8; +} + + +void RigidBody2D::set_friction(real_t p_friction){ + + ERR_FAIL_COND(p_friction<0 || p_friction>1); + + friction=p_friction; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_FRICTION,friction); + +} +real_t RigidBody2D::get_friction() const{ + + return friction; +} + +void RigidBody2D::set_bounce(real_t p_bounce){ + + ERR_FAIL_COND(p_bounce<0 || p_bounce>1); + + bounce=p_bounce; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_BOUNCE,bounce); + +} +real_t RigidBody2D::get_bounce() const{ + + return bounce; +} + +void RigidBody2D::set_axis_velocity(const Vector2& p_axis) { + + Vector2 v = state? state->get_linear_velocity() : linear_velocity; + Vector2 axis = p_axis.normalized(); + v-=axis*axis.dot(v); + v+=p_axis; + if (state) { + set_linear_velocity(v); + } else { + Physics2DServer::get_singleton()->body_set_axis_velocity(get_rid(),p_axis); + linear_velocity=v; + } +} + +void RigidBody2D::set_linear_velocity(const Vector2& p_velocity){ + + linear_velocity=p_velocity; + if (state) + state->set_linear_velocity(linear_velocity); + else { + + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_LINEAR_VELOCITY,linear_velocity); + } + +} + +Vector2 RigidBody2D::get_linear_velocity() const{ + + return linear_velocity; +} + +void RigidBody2D::set_angular_velocity(real_t p_velocity){ + + angular_velocity=p_velocity; + if (state) + state->set_angular_velocity(angular_velocity); + else + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_ANGULAR_VELOCITY,angular_velocity); +} +real_t RigidBody2D::get_angular_velocity() const{ + + return angular_velocity; +} + +void RigidBody2D::set_use_custom_integrator(bool p_enable){ + + if (custom_integrator==p_enable) + return; + + custom_integrator=p_enable; + Physics2DServer::get_singleton()->body_set_omit_force_integration(get_rid(),p_enable); + + +} +bool RigidBody2D::is_using_custom_integrator(){ + + return custom_integrator; +} + +void RigidBody2D::set_active(bool p_active) { + + active=p_active; + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_SLEEPING,!active); + +} + +void RigidBody2D::set_can_sleep(bool p_active) { + + can_sleep=p_active; + Physics2DServer::get_singleton()->body_set_state(get_rid(),Physics2DServer::BODY_STATE_CAN_SLEEP,p_active); +} + +bool RigidBody2D::is_able_to_sleep() const { + + return can_sleep; +} + +bool RigidBody2D::is_active() const { + + return active; +} + +void RigidBody2D::set_max_contacts_reported(int p_amount) { + + max_contacts_reported=p_amount; + Physics2DServer::get_singleton()->body_set_max_contacts_reported(get_rid(),p_amount); +} + +int RigidBody2D::get_max_contacts_reported() const{ + + return max_contacts_reported; +} + +void RigidBody2D::apply_impulse(const Vector2& p_pos, const Vector2& p_impulse) { + + Physics2DServer::get_singleton()->body_apply_impulse(get_rid(),p_pos,p_impulse); +} + +void RigidBody2D::set_applied_force(const Vector2& p_force) { + + Physics2DServer::get_singleton()->body_set_applied_force(get_rid(), p_force); +}; + +Vector2 RigidBody2D::get_applied_force() const { + + return Physics2DServer::get_singleton()->body_get_applied_force(get_rid()); +}; + +void RigidBody2D::set_use_continuous_collision_detection(bool p_enable) { + + ccd=p_enable; + Physics2DServer::get_singleton()->body_set_enable_continuous_collision_detection(get_rid(),p_enable); +} + +bool RigidBody2D::is_using_continuous_collision_detection() const { + + + return ccd; +} + + +void RigidBody2D::set_contact_monitor(bool p_enabled) { + + if (p_enabled==is_contact_monitor_enabled()) + return; + + if (!p_enabled) { + + for(Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.front();E;E=E->next()) { + + //clean up mess + } + + memdelete( contact_monitor ); + contact_monitor=NULL; + } else { + + contact_monitor = memnew( ContactMonitor ); + } + +} + +bool RigidBody2D::is_contact_monitor_enabled() const { + + return contact_monitor!=NULL; +} + + + +void RigidBody2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_mode","mode"),&RigidBody2D::set_mode); + ObjectTypeDB::bind_method(_MD("get_mode"),&RigidBody2D::get_mode); + + ObjectTypeDB::bind_method(_MD("set_mass","mass"),&RigidBody2D::set_mass); + ObjectTypeDB::bind_method(_MD("get_mass"),&RigidBody2D::get_mass); + + ObjectTypeDB::bind_method(_MD("set_weight","weight"),&RigidBody2D::set_weight); + ObjectTypeDB::bind_method(_MD("get_weight"),&RigidBody2D::get_weight); + + ObjectTypeDB::bind_method(_MD("set_friction","friction"),&RigidBody2D::set_friction); + ObjectTypeDB::bind_method(_MD("get_friction"),&RigidBody2D::get_friction); + + ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&RigidBody2D::set_bounce); + ObjectTypeDB::bind_method(_MD("get_bounce"),&RigidBody2D::get_bounce); + + ObjectTypeDB::bind_method(_MD("set_linear_velocity","linear_velocity"),&RigidBody2D::set_linear_velocity); + ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&RigidBody2D::get_linear_velocity); + + ObjectTypeDB::bind_method(_MD("set_angular_velocity","angular_velocity"),&RigidBody2D::set_angular_velocity); + ObjectTypeDB::bind_method(_MD("get_angular_velocity"),&RigidBody2D::get_angular_velocity); + + ObjectTypeDB::bind_method(_MD("set_max_contacts_reported","amount"),&RigidBody2D::set_max_contacts_reported); + ObjectTypeDB::bind_method(_MD("get_max_contacts_reported"),&RigidBody2D::get_max_contacts_reported); + + ObjectTypeDB::bind_method(_MD("set_use_custom_integrator","enable"),&RigidBody2D::set_use_custom_integrator); + ObjectTypeDB::bind_method(_MD("is_using_custom_integrator"),&RigidBody2D::is_using_custom_integrator); + + ObjectTypeDB::bind_method(_MD("set_contact_monitor","enabled"),&RigidBody2D::set_contact_monitor); + ObjectTypeDB::bind_method(_MD("is_contact_monitor_enabled"),&RigidBody2D::is_contact_monitor_enabled); + + ObjectTypeDB::bind_method(_MD("set_use_continuous_collision_detection","enable"),&RigidBody2D::set_use_continuous_collision_detection); + ObjectTypeDB::bind_method(_MD("is_using_continuous_collision_detection"),&RigidBody2D::is_using_continuous_collision_detection); + + ObjectTypeDB::bind_method(_MD("set_axis_velocity","axis_velocity"),&RigidBody2D::set_axis_velocity); + ObjectTypeDB::bind_method(_MD("apply_impulse","pos","impulse"),&RigidBody2D::apply_impulse); + + ObjectTypeDB::bind_method(_MD("set_applied_force","force"),&RigidBody2D::set_applied_force); + ObjectTypeDB::bind_method(_MD("get_applied_force"),&RigidBody2D::get_applied_force); + + ObjectTypeDB::bind_method(_MD("set_active","active"),&RigidBody2D::set_active); + ObjectTypeDB::bind_method(_MD("is_active"),&RigidBody2D::is_active); + + ObjectTypeDB::bind_method(_MD("set_can_sleep","able_to_sleep"),&RigidBody2D::set_can_sleep); + ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody2D::is_able_to_sleep); + + ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody2D::_direct_state_changed); + ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody2D::_body_enter_scene); + ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody2D::_body_exit_scene); + + BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:Physics2DDirectBodyState"))); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Rigid,Static,Character,Static Active"),_SCS("set_mode"),_SCS("get_mode")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"mass",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01"),_SCS("set_mass"),_SCS("get_mass")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"weight",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01",PROPERTY_USAGE_EDITOR),_SCS("set_weight"),_SCS("get_weight")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"custom_integrator"),_SCS("set_use_custom_integrator"),_SCS("is_using_custom_integrator")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"continuous_cd"),_SCS("set_use_continuous_collision_detection"),_SCS("is_using_continuous_collision_detection")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"contact_monitor"),_SCS("set_contact_monitor"),_SCS("is_contact_monitor_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"active"),_SCS("set_active"),_SCS("is_active")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"can_sleep"),_SCS("set_can_sleep"),_SCS("is_able_to_sleep")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"velocity/angular"),_SCS("set_angular_velocity"),_SCS("get_angular_velocity")); + + ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); + ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); + ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body"))); + ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body"))); + + BIND_CONSTANT( MODE_STATIC ); + BIND_CONSTANT( MODE_STATIC_ACTIVE ); + BIND_CONSTANT( MODE_RIGID ); + BIND_CONSTANT( MODE_CHARACTER ); +} + +RigidBody2D::RigidBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_RIGID) { + + mode=MODE_RIGID; + + bounce=0; + mass=1; + friction=1; + max_contacts_reported=0; + state=NULL; + + angular_velocity=0; + active=true; + ccd=false; + + custom_integrator=false; + contact_monitor=NULL; + can_sleep=true; + + Physics2DServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed"); +} + +RigidBody2D::~RigidBody2D() { + + if (contact_monitor) + memdelete( contact_monitor ); + + + +} + diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h new file mode 100644 index 0000000000..9eff59d8a7 --- /dev/null +++ b/scene/2d/physics_body_2d.h @@ -0,0 +1,232 @@ +/*************************************************************************/ +/* physics_body_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef PHYSICS_BODY_2D_H +#define PHYSICS_BODY_2D_H + +#include "scene/2d/collision_object_2d.h" +#include "servers/physics_2d_server.h" +#include "vset.h" + + +class PhysicsBody2D : public CollisionObject2D { + + OBJ_TYPE(PhysicsBody2D,CollisionObject2D); + +protected: + + void _notification(int p_what); + PhysicsBody2D(Physics2DServer::BodyMode p_mode); +public: + + PhysicsBody2D(); + +}; + +class StaticBody2D : public PhysicsBody2D { + + OBJ_TYPE(StaticBody2D,PhysicsBody2D); + + Matrix32 *pre_xform; + //RID query; + bool setting; + bool pending; + bool simulating_motion; + Vector2 constant_linear_velocity; + real_t constant_angular_velocity; + void _update_xform(); + void _state_notify(Object *p_object); + + real_t bounce; + real_t friction; + + +protected: + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_friction(real_t p_friction); + real_t get_friction() const; + + void set_bounce(real_t p_bounce); + real_t get_bounce() const; + + void set_simulate_motion(bool p_enable); + bool is_simulating_motion() const; + + void set_constant_linear_velocity(const Vector2& p_vel); + void set_constant_angular_velocity(real_t p_vel); + + Vector2 get_constant_linear_velocity() const; + real_t get_constant_angular_velocity() const; + + StaticBody2D(); + ~StaticBody2D(); + +}; + +class RigidBody2D : public PhysicsBody2D { + + OBJ_TYPE(RigidBody2D,PhysicsBody2D); +public: + + enum Mode { + MODE_RIGID, + MODE_STATIC, + MODE_CHARACTER, + MODE_STATIC_ACTIVE, + }; +private: + + bool can_sleep; + Physics2DDirectBodyState *state; + Mode mode; + + real_t bounce; + real_t mass; + real_t friction; + + Vector2 linear_velocity; + real_t angular_velocity; + bool active; + bool ccd; + + + int max_contacts_reported; + + bool custom_integrator; + + + struct ShapePair { + + int body_shape; + int local_shape; + bool tagged; + bool operator<(const ShapePair& p_sp) const { + if (body_shape==p_sp.body_shape) + return local_shape < p_sp.local_shape; + else + return body_shape < p_sp.body_shape; + } + + ShapePair() {} + ShapePair(int p_bs, int p_ls) { body_shape=p_bs; local_shape=p_ls; } + }; + struct RigidBody2D_RemoveAction { + + + ObjectID body_id; + ShapePair pair; + + }; + struct BodyState { + + int rc; + bool in_scene; + VSet<ShapePair> shapes; + }; + + struct ContactMonitor { + + + Map<ObjectID,BodyState> body_map; + + }; + + + ContactMonitor *contact_monitor; + void _body_enter_scene(ObjectID p_id); + void _body_exit_scene(ObjectID p_id); + + + void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape); + void _direct_state_changed(Object *p_state); + + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_mode(Mode p_mode); + Mode get_mode() const; + + void set_mass(real_t p_mass); + real_t get_mass() const; + + void set_weight(real_t p_weight); + real_t get_weight() const; + + void set_friction(real_t p_friction); + real_t get_friction() const; + + void set_bounce(real_t p_bounce); + real_t get_bounce() const; + + void set_linear_velocity(const Vector2& p_velocity); + Vector2 get_linear_velocity() const; + + void set_axis_velocity(const Vector2& p_axis); + + void set_angular_velocity(real_t p_velocity); + real_t get_angular_velocity() const; + + void set_use_custom_integrator(bool p_enable); + bool is_using_custom_integrator(); + + void set_active(bool p_active); + bool is_active() const; + + void set_can_sleep(bool p_active); + bool is_able_to_sleep() const; + + void set_contact_monitor(bool p_enabled); + bool is_contact_monitor_enabled() const; + + void set_max_contacts_reported(int p_amount); + int get_max_contacts_reported() const; + + void set_use_continuous_collision_detection(bool p_enable); + bool is_using_continuous_collision_detection() const; + + void apply_impulse(const Vector2& p_pos, const Vector2& p_impulse); + + void set_applied_force(const Vector2& p_force); + Vector2 get_applied_force() const; + + RigidBody2D(); + ~RigidBody2D(); + +}; + +VARIANT_ENUM_CAST(RigidBody2D::Mode); +#endif // PHYSICS_BODY_2D_H diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp new file mode 100644 index 0000000000..ca3be9aa8f --- /dev/null +++ b/scene/2d/position_2d.cpp @@ -0,0 +1,65 @@ +/*************************************************************************/ +/* position_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "position_2d.h" +#include "scene/resources/texture.h" + +void Position2D::_draw_cross() { + + draw_line(Point2(-10,0),Point2(+10,0),Color(1,0.5,0.5)); + draw_line(Point2(0,-10),Point2(0,+10),Color(0.5,1,0.5)); + +} + +Rect2 Position2D::get_item_rect() const { + + return Rect2(Point2(-10,-10),Size2(20,20)); +} + +void Position2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + update(); + } break; + case NOTIFICATION_DRAW: { + if (!is_inside_scene()) + break; + if (get_scene()->is_editor_hint()) + _draw_cross(); + + } break; + } + +} + +Position2D::Position2D() +{ +} diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h new file mode 100644 index 0000000000..caabf98eae --- /dev/null +++ b/scene/2d/position_2d.h @@ -0,0 +1,49 @@ +/*************************************************************************/ +/* position_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef POSITION_2D_H +#define POSITION_2D_H + + +#include "scene/2d/node_2d.h" + +class Position2D : public Node2D { + + OBJ_TYPE(Position2D,Node2D) + + void _draw_cross(); +protected: + + void _notification(int p_what); +public: + + virtual Rect2 get_item_rect() const; + Position2D(); +}; + +#endif // POSITION_2D_H diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp new file mode 100644 index 0000000000..a2c57b8ffb --- /dev/null +++ b/scene/2d/ray_cast_2d.cpp @@ -0,0 +1,198 @@ +/*************************************************************************/ +/* ray_cast_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "ray_cast_2d.h"
+#include "servers/physics_2d_server.h"
+
+void RayCast2D::set_cast_to(const Vector2& p_point) {
+
+ cast_to=p_point;
+ if (is_inside_scene() && get_scene()->is_editor_hint())
+ update();
+
+}
+
+Vector2 RayCast2D::get_cast_to() const{
+
+ return cast_to;
+}
+
+bool RayCast2D::is_colliding() const{
+
+ return collided;
+}
+Object *RayCast2D::get_collider() const{
+
+ if (against==0)
+ return NULL;
+
+ return ObjectDB::get_instance(against);
+}
+
+int RayCast2D::get_collider_shape() const {
+
+ return against_shape;
+}
+Vector2 RayCast2D::get_collision_point() const{
+
+ return collision_point;
+}
+Vector2 RayCast2D::get_collision_normal() const{
+
+ return collision_normal;
+}
+
+
+void RayCast2D::set_enabled(bool p_enabled) {
+
+ enabled=p_enabled;
+ if (is_inside_scene() && !get_scene()->is_editor_hint())
+ set_fixed_process(p_enabled);
+ if (!p_enabled)
+ collided=false;
+
+}
+
+
+bool RayCast2D::is_enabled() const {
+
+
+ return enabled;
+}
+
+
+void RayCast2D::_notification(int p_what) {
+
+ switch(p_what) {
+
+ case NOTIFICATION_ENTER_SCENE: {
+
+ if (enabled && !get_scene()->is_editor_hint())
+ set_fixed_process(true);
+ else
+ set_fixed_process(false);
+
+ } break;
+ case NOTIFICATION_EXIT_SCENE: {
+
+ if (enabled)
+ set_fixed_process(false);
+
+ } break;
+#ifdef TOOLS_ENABLED
+ case NOTIFICATION_DRAW: {
+
+ if (!get_scene()->is_editor_hint())
+ break;
+ Matrix32 xf;
+ xf.rotate(cast_to.atan2());
+ xf.translate(Vector2(0,cast_to.length()));
+
+ //Vector2 tip = Vector2(0,s->get_length());
+ Color dcol(0.9,0.2,0.2,0.4);
+ draw_line(Vector2(),cast_to,dcol,3);
+ Vector<Vector2> pts;
+ float tsize=4;
+ pts.push_back(xf.xform(Vector2(0,tsize)));
+ pts.push_back(xf.xform(Vector2(0.707*tsize,0)));
+ pts.push_back(xf.xform(Vector2(-0.707*tsize,0)));
+ Vector<Color> cols;
+ for(int i=0;i<3;i++)
+ cols.push_back(dcol);
+
+ draw_primitive(pts,cols,Vector<Vector2>()); //small arrow
+
+ } break;
+#endif
+
+ case NOTIFICATION_FIXED_PROCESS: {
+
+ if (!enabled)
+ break;
+
+
+
+ Ref<World2D> w2d = get_world_2d();
+ ERR_BREAK( w2d.is_null() );
+
+ Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(w2d->get_space());
+ ERR_BREAK( !dss );
+
+ Matrix32 gt = get_global_transform();
+
+ Vector2 to = cast_to;
+ if (to==Vector2())
+ to=Vector2(0,0.01);
+
+ Physics2DDirectSpaceState::RayResult rr;
+
+ if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr)) {
+
+ collided=true;
+ against=rr.collider_id;
+ collision_point=rr.position;
+ collision_normal=rr.normal;
+ against_shape=rr.shape;
+ } else {
+ collided=false;
+ }
+
+
+
+ } break;
+ }
+}
+
+void RayCast2D::_bind_methods() {
+
+
+ ObjectTypeDB::bind_method(_MD("set_enabled","enabled"),&RayCast2D::set_enabled);
+ ObjectTypeDB::bind_method(_MD("is_enabled"),&RayCast2D::is_enabled);
+
+ ObjectTypeDB::bind_method(_MD("set_cast_to","local_point"),&RayCast2D::set_cast_to);
+ ObjectTypeDB::bind_method(_MD("get_cast_to"),&RayCast2D::get_cast_to);
+
+ ObjectTypeDB::bind_method(_MD("is_colliding"),&RayCast2D::is_colliding);
+
+ ObjectTypeDB::bind_method(_MD("get_collider"),&RayCast2D::get_collider);
+ ObjectTypeDB::bind_method(_MD("get_collider_shape"),&RayCast2D::get_collider_shape);
+ ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast2D::get_collision_point);
+ ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast2D::get_collision_normal);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled"));
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to"));
+}
+
+RayCast2D::RayCast2D() {
+
+ enabled=false;
+ against=0;
+ collided=false;
+ against_shape=0;
+ cast_to=Vector2(0,50);
+}
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h new file mode 100644 index 0000000000..62bcb946a6 --- /dev/null +++ b/scene/2d/ray_cast_2d.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* ray_cast_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef RAY_CAST_2D_H
+#define RAY_CAST_2D_H
+
+#include "scene/2d/node_2d.h"
+
+class RayCast2D : public Node2D {
+
+ OBJ_TYPE(RayCast2D,Node2D);
+
+
+ bool enabled;
+ bool collided;
+ ObjectID against;
+ int against_shape;
+ Vector2 collision_point;
+ Vector2 collision_normal;
+
+ Vector2 cast_to;
+protected:
+
+ void _notification(int p_what);
+ static void _bind_methods();
+public:
+
+ void set_enabled(bool p_enabled);
+ bool is_enabled() const;
+
+ void set_cast_to(const Vector2& p_point);
+ Vector2 get_cast_to() const;
+
+ bool is_colliding() const;
+ Object *get_collider() const;
+ int get_collider_shape() const;
+ Vector2 get_collision_point() const;
+ Vector2 get_collision_normal() const;
+
+ RayCast2D();
+};
+
+#endif // RAY_CAST_2D_H
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp new file mode 100644 index 0000000000..80d038f6f8 --- /dev/null +++ b/scene/2d/remote_transform_2d.cpp @@ -0,0 +1,122 @@ +/*************************************************************************/ +/* remote_transform_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "remote_transform_2d.h" +#include "scene/scene_string_names.h" + +void RemoteTransform2D::_update_cache() { + + cache=0; + if (has_node(remote_node)) { + Node *node = get_node(remote_node); + if (!node || this==node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) { + return; + } + + cache=node->get_instance_ID(); + } +} + +void RemoteTransform2D::_update_remote() { + + + if (!is_inside_scene()) + return; + + if (!cache) + return; + + Object *obj = ObjectDB::get_instance(cache); + if (!obj) + return; + + Node2D *n = obj->cast_to<Node2D>(); + if (!n) + return; + + if (!n->is_inside_scene()) + return; + + //todo make faster + n->set_global_transform(get_global_transform()); + +} + +void RemoteTransform2D::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_READY: { + + _update_cache(); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + if (!is_inside_scene()) + break; + + if (cache) { + + _update_remote(); + + } + + } break; + + } +} + + +void RemoteTransform2D::set_remote_node(const NodePath& p_remote_node) { + + remote_node=p_remote_node; + if (is_inside_scene()) + _update_cache(); +} + +NodePath RemoteTransform2D::get_remote_node() const{ + + return remote_node; +} + + +void RemoteTransform2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_remote_node","path"),&RemoteTransform2D::set_remote_node); + ObjectTypeDB::bind_method(_MD("get_remote_node"),&RemoteTransform2D::get_remote_node); + + ADD_PROPERTY( PropertyInfo(Variant::NODE_PATH,"remote_path"),_SCS("set_remote_node"),_SCS("get_remote_node")); +} + +RemoteTransform2D::RemoteTransform2D() { + + cache=0; + +} + + diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h new file mode 100644 index 0000000000..9561e72255 --- /dev/null +++ b/scene/2d/remote_transform_2d.h @@ -0,0 +1,52 @@ +/*************************************************************************/ +/* remote_transform_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "scene/2d/node_2d.h" + +class RemoteTransform2D : public Node2D { + + OBJ_TYPE(RemoteTransform2D,Node2D); + + NodePath remote_node; + + ObjectID cache; + + void _update_remote(); + void _update_cache(); + void _node_exited_scene(); +protected: + + static void _bind_methods(); + void _notification(int p_what); +public: + + void set_remote_node(const NodePath& p_remote_node); + NodePath get_remote_node() const; + + RemoteTransform2D(); +}; diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp new file mode 100644 index 0000000000..bc1734ec06 --- /dev/null +++ b/scene/2d/sample_player_2d.cpp @@ -0,0 +1,252 @@ +/*************************************************************************/ +/* sample_player_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "sample_player_2d.h" + +#include "servers/audio_server.h" +#include "servers/audio_server.h" +#include "servers/spatial_sound_server.h" + + +bool SamplePlayer2D::_set(const StringName& p_name, const Variant& p_value) { + + String name=p_name; + + if (name=="play/play") { + if (library.is_valid()) { + + String what=p_value; + if (what=="") + stop_all(); + else + play(what); + + played_back=what; + } + } else + return false; + + return true; +} + +bool SamplePlayer2D::_get(const StringName& p_name,Variant &r_ret) const { + + + String name=p_name; + + if (name=="play/play") { + r_ret=played_back; + } else + return false; + + return true; +} + +void SamplePlayer2D::_get_property_list(List<PropertyInfo> *p_list) const { + + String en=""; + if (library.is_valid()) { + List<StringName> samples; + Ref<SampleLibrary> ncl=library; + ncl->get_sample_list(&samples); + for (List<StringName>::Element *E=samples.front();E;E=E->next()) { + + en+=","; + en+=E->get(); + } + } + + p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR)); +} + +void SamplePlayer2D::_notification(int p_what) { + + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony); + + + } break; + } + +} + +void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary>& p_library) { + + library=p_library; +} + +Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const { + + return library; +} + +void SamplePlayer2D::set_polyphony(int p_voice_count) { + + ERR_FAIL_COND(p_voice_count<0 || p_voice_count>64); + polyphony=p_voice_count; + if (get_source_rid().is_valid()) + SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony); + +} + +int SamplePlayer2D::get_polyphony() const { + + return polyphony; +} + +SamplePlayer2D::VoiceID SamplePlayer2D::play(const String& p_sample,int p_voice) { + + if (!get_source_rid().is_valid()) + return INVALID_VOICE; + if (library.is_null()) + return INVALID_VOICE; + if (!library->has_sample(p_sample)) + return INVALID_VOICE; + Ref<Sample> sample = library->get_sample(p_sample); + float vol_change = library->sample_get_volume_db(p_sample); + float pitch_change = library->sample_get_pitch_scale(p_sample); + + VoiceID vid = SpatialSound2DServer::get_singleton()->source_play_sample(get_source_rid(),sample->get_rid(),sample->get_mix_rate()*pitch_change,p_voice); + if (vol_change) + SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(),vid,vol_change); + + + if (random_pitch_scale) { + float ps = Math::random(-random_pitch_scale,random_pitch_scale); + if (ps>0) + ps=1.0+ps; + else + ps=1.0/(1.0-ps); + SpatialSound2DServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(),vid,ps*pitch_change); + + } + + return vid; +} +//voices +void SamplePlayer2D::voice_set_pitch_scale(VoiceID p_voice, float p_pitch_scale) { + + if (!get_source_rid().is_valid()) + return; + + SpatialSound2DServer::get_singleton()->source_voice_set_pitch_scale(get_source_rid(),p_voice,p_pitch_scale); + +} + +void SamplePlayer2D::voice_set_volume_scale_db(VoiceID p_voice, float p_volume_db) { + + if (!get_source_rid().is_valid()) + return; + SpatialSound2DServer::get_singleton()->source_voice_set_volume_scale_db(get_source_rid(),p_voice,p_volume_db); + +} + +bool SamplePlayer2D::is_voice_active(VoiceID p_voice) const { + + if (!get_source_rid().is_valid()) + return false; + return SpatialSound2DServer::get_singleton()->source_is_voice_active(get_source_rid(),p_voice); + +} + +void SamplePlayer2D::stop_voice(VoiceID p_voice) { + + if (!get_source_rid().is_valid()) + return; + SpatialSound2DServer::get_singleton()->source_stop_voice(get_source_rid(),p_voice); + +} + +void SamplePlayer2D::stop_all() { + + if (!get_source_rid().is_valid()) + return; + + for(int i=0;i<polyphony;i++) { + + SpatialSound2DServer::get_singleton()->source_stop_voice(get_source_rid(),i); + } +} + +void SamplePlayer2D::set_random_pitch_scale(float p_scale) { + random_pitch_scale=p_scale; +} + +float SamplePlayer2D::get_random_pitch_scale() const { + + return random_pitch_scale; +} + + +void SamplePlayer2D::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SamplePlayer2D::set_sample_library); + ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SamplePlayer2D::get_sample_library); + + ObjectTypeDB::bind_method(_MD("set_polyphony","voices"),&SamplePlayer2D::set_polyphony); + ObjectTypeDB::bind_method(_MD("get_polyphony"),&SamplePlayer2D::get_polyphony); + + ObjectTypeDB::bind_method(_MD("play","sample","voice"),&SamplePlayer2D::play,DEFVAL(NEXT_VOICE)); + //voices,DEV + ObjectTypeDB::bind_method(_MD("voice_set_pitch_scale","voice","ratio"),&SamplePlayer2D::voice_set_pitch_scale); + ObjectTypeDB::bind_method(_MD("voice_set_volume_scale_db","voice","db"),&SamplePlayer2D::voice_set_volume_scale_db); + + ObjectTypeDB::bind_method(_MD("is_voice_active","voice"),&SamplePlayer2D::is_voice_active); + ObjectTypeDB::bind_method(_MD("stop_voice","voice"),&SamplePlayer2D::stop_voice); + ObjectTypeDB::bind_method(_MD("stop_all"),&SamplePlayer2D::stop_all); + + ObjectTypeDB::bind_method(_MD("set_random_pitch_scale","val"),&SamplePlayer2D::set_random_pitch_scale); + ObjectTypeDB::bind_method(_MD("get_random_pitch_scale"),&SamplePlayer2D::get_random_pitch_scale); + + BIND_CONSTANT( INVALID_VOICE ); + BIND_CONSTANT( NEXT_VOICE ); + + ADD_PROPERTY( PropertyInfo( Variant::INT, "config/polyphony", PROPERTY_HINT_RANGE, "1,64,1"),_SCS("set_polyphony"),_SCS("get_polyphony")); + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "config/samples", PROPERTY_HINT_RESOURCE_TYPE,"SampleLibrary"),_SCS("set_sample_library"),_SCS("get_sample_library")); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "config/pitch_random", PROPERTY_HINT_RESOURCE_TYPE,"SampleLibrary"),_SCS("set_random_pitch_scale"),_SCS("get_random_pitch_scale")); + + +} + + +SamplePlayer2D::SamplePlayer2D() { + + polyphony=1; + random_pitch_scale=0; + +} + +SamplePlayer2D::~SamplePlayer2D() { + + +} diff --git a/scene/2d/sample_player_2d.h b/scene/2d/sample_player_2d.h new file mode 100644 index 0000000000..d04abae244 --- /dev/null +++ b/scene/2d/sample_player_2d.h @@ -0,0 +1,92 @@ +/*************************************************************************/ +/* sample_player_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SAMPLE_PLAYER_2D_H +#define SAMPLE_PLAYER_2D_H + +#include "scene/2d/sound_player_2d.h" +#include "scene/resources/sample_library.h" + +class SamplePlayer2D : public SoundPlayer2D { + + OBJ_TYPE(SamplePlayer2D,SoundPlayer2D); +public: + + enum { + + INVALID_VOICE=SpatialSoundServer::SOURCE_INVALID_VOICE, + NEXT_VOICE=SpatialSoundServer::SOURCE_NEXT_VOICE + }; + + typedef int VoiceID; + + +private: + + Ref<SampleLibrary> library; + int polyphony; + String played_back; + float random_pitch_scale; + +protected: + + bool _set(const StringName& p_name, const Variant& p_value); + bool _get(const StringName& p_name,Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + + void _notification(int p_what); + + static void _bind_methods(); + +public: + + void set_sample_library(const Ref<SampleLibrary>& p_library); + Ref<SampleLibrary> get_sample_library() const; + + void set_polyphony(int p_voice_count); + int get_polyphony() const; + + VoiceID play(const String& p_sample,int p_voice=NEXT_VOICE); + //voices + void voice_set_pitch_scale(VoiceID p_voice, float p_pitch_scale); + void voice_set_volume_scale_db(VoiceID p_voice, float p_volume_db); + + bool is_voice_active(VoiceID p_voice) const; + void stop_voice(VoiceID p_voice); + void stop_all(); + + void set_random_pitch_scale(float p_scale); + float get_random_pitch_scale() const; + + SamplePlayer2D(); + ~SamplePlayer2D(); + + +}; + +#endif // SAMPLE_PLAYER_2D_H diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp new file mode 100644 index 0000000000..f386dc63e8 --- /dev/null +++ b/scene/2d/screen_button.cpp @@ -0,0 +1,372 @@ +/*************************************************************************/ +/* screen_button.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "screen_button.h" +#include "os/os.h" +#include "input_map.h" +#include "os/input.h" + +void TouchScreenButton::set_texture(const Ref<Texture>& p_texture) { + + texture=p_texture; + update(); +} + +Ref<Texture> TouchScreenButton::get_texture() const{ + + return texture; +} + +void TouchScreenButton::set_texture_pressed(const Ref<Texture>& p_texture_pressed) { + + texture_pressed=p_texture_pressed; + update(); +} + +Ref<Texture> TouchScreenButton::get_texture_pressed() const{ + + return texture_pressed; +} + +void TouchScreenButton::set_bitmask(const Ref<BitMap>& p_bitmask){ + + bitmask=p_bitmask; +} + +Ref<BitMap> TouchScreenButton::get_bitmask() const{ + + return bitmask; +} + +void TouchScreenButton::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_DRAW: { + + if (!is_inside_scene()) + return; + if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY) + return; + + if (finger_pressed!=-1) { + + if (texture_pressed.is_valid()) + draw_texture(texture_pressed,Point2()); + else if (texture.is_valid()) + draw_texture(texture,Point2()); + + } else { + if (texture.is_valid()) + draw_texture(texture,Point2()); + } + + } break; + case NOTIFICATION_ENTER_SCENE: { + + if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY) + return; + update(); + set_process_input(true); + if (action.operator String()!="" && InputMap::get_singleton()->has_action(action)) { + action_id=InputMap::get_singleton()->get_action_id(action); + } else { + action_id=-1; + } + } break; + } +} + + +bool TouchScreenButton::is_pressed() const{ + + return finger_pressed!=-1; +} + +void TouchScreenButton::set_action(const String& p_action) { + + action=p_action; + if (action.operator String()!="" && InputMap::get_singleton()->has_action(action)) { + action_id=InputMap::get_singleton()->get_action_id(action); + } else { + action_id=-1; + } + +} + +String TouchScreenButton::get_action() const { + + return action; +} + +void TouchScreenButton::_input(const InputEvent& p_event) { + + if (!get_scene()) + return; + + if (passby_press) { + + if (p_event.type==InputEvent::SCREEN_TOUCH && !p_event.screen_touch.pressed && finger_pressed==p_event.screen_touch.index) { + + emit_signal("released"); + + if (action_id!=-1) { + + Input::get_singleton()->action_release(action); + InputEvent ie; + ie.type=InputEvent::ACTION; + ie.ID=0; + ie.action.action=action_id; + ie.action.pressed=false; + get_scene()->input_event(ie); + } + finger_pressed=-1; + + update(); + + } + + if ((p_event.type==InputEvent::SCREEN_TOUCH && p_event.screen_touch.pressed)|| p_event.type==InputEvent::SCREEN_DRAG) { + + if (finger_pressed==-1 || p_event.screen_touch.index==finger_pressed) { + + Point2 coord = (get_viewport_transform() * get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y)); + + bool touched=false; + if (bitmask.is_valid()) { + + if (Rect2(Point2(),bitmask->get_size()).has_point(coord)) { + + if (bitmask->get_bit(coord)) + touched=true; + } + } else { + + touched=Rect2(Point2(),texture->get_size()).has_point(coord); + } + + + + if (touched) { + + if (finger_pressed==-1) { + finger_pressed=p_event.screen_touch.index; + //emit change stuff + emit_signal("pressed"); + if (action_id!=-1) { + + Input::get_singleton()->action_press(action); + InputEvent ie; + ie.type=InputEvent::ACTION; + ie.ID=0; + ie.action.action=action_id; + ie.action.pressed=true; + get_scene()->input_event(ie); + } + + update(); + } + + } else { + + if (finger_pressed!=-1) { + + emit_signal("released"); + + if (action_id!=-1) { + + Input::get_singleton()->action_release(action); + InputEvent ie; + ie.type=InputEvent::ACTION; + ie.ID=0; + ie.action.action=action_id; + ie.action.pressed=false; + get_scene()->input_event(ie); + } + finger_pressed=-1; + + update(); + } + } + + } + + + } + + } else { + + if (p_event.type==InputEvent::SCREEN_TOUCH) { + + if (p_event.screen_touch.pressed) { + + if (!is_visible()) + return; + + if (finger_pressed!=-1) + return; //already fingering + + Point2 coord = (get_viewport_transform() * get_global_transform()).affine_inverse().xform(Point2(p_event.screen_touch.x,p_event.screen_touch.y)); + + bool touched=false; + if (bitmask.is_valid()) { + + if (Rect2(Point2(),bitmask->get_size()).has_point(coord)) { + + if (bitmask->get_bit(coord)) + touched=true; + } + } else { + + touched=Rect2(Point2(),texture->get_size()).has_point(coord); + } + + + + if (touched) { + + finger_pressed=p_event.screen_touch.index; + //emit change stuff + emit_signal("pressed"); + if (action_id!=-1) { + + Input::get_singleton()->action_press(action); + InputEvent ie; + ie.type=InputEvent::ACTION; + ie.ID=0; + ie.action.action=action_id; + ie.action.pressed=true; + get_scene()->input_event(ie); + } + update(); + + } + } else { + + + if (p_event.screen_touch.index==finger_pressed) { + //untouch + + emit_signal("released"); + + if (action_id!=-1) { + + Input::get_singleton()->action_release(action); + InputEvent ie; + ie.type=InputEvent::ACTION; + ie.ID=0; + ie.action.action=action_id; + ie.action.pressed=false; + get_scene()->input_event(ie); + } + finger_pressed=-1; + update(); + } + } + } + } +} + +Rect2 TouchScreenButton::get_item_rect() const { + + if (texture.is_null()) + return Rect2(0,0,1,1); + //if (texture.is_null()) + // return CanvasItem::get_item_rect(); + + return Rect2(Size2(),texture->get_size()); +} + + +void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) { + visibility=p_mode; + update(); +} + +TouchScreenButton::VisibilityMode TouchScreenButton::get_visibility_mode() const { + + return visibility; +} + +void TouchScreenButton::set_passby_press(bool p_enable) { + + passby_press=p_enable; +} + +bool TouchScreenButton::is_passby_press_enabled() const{ + + return passby_press; +} + + + +void TouchScreenButton::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_texture","texture"),&TouchScreenButton::set_texture); + ObjectTypeDB::bind_method(_MD("get_texture"),&TouchScreenButton::get_texture); + + ObjectTypeDB::bind_method(_MD("set_texture_pressed","texture_pressed"),&TouchScreenButton::set_texture_pressed); + ObjectTypeDB::bind_method(_MD("get_texture_pressed"),&TouchScreenButton::get_texture_pressed); + + ObjectTypeDB::bind_method(_MD("set_bitmask","bitmask"),&TouchScreenButton::set_bitmask); + ObjectTypeDB::bind_method(_MD("get_bitmask"),&TouchScreenButton::get_bitmask); + + ObjectTypeDB::bind_method(_MD("set_action","action"),&TouchScreenButton::set_action); + ObjectTypeDB::bind_method(_MD("get_action"),&TouchScreenButton::get_action); + + ObjectTypeDB::bind_method(_MD("set_visibility_mode","mode"),&TouchScreenButton::set_visibility_mode); + ObjectTypeDB::bind_method(_MD("get_visibility_mode"),&TouchScreenButton::get_visibility_mode); + + ObjectTypeDB::bind_method(_MD("set_passby_press","enabled"),&TouchScreenButton::set_passby_press); + ObjectTypeDB::bind_method(_MD("is_passby_press_enabled"),&TouchScreenButton::is_passby_press_enabled); + + ObjectTypeDB::bind_method(_MD("is_pressed"),&TouchScreenButton::is_pressed); + + ObjectTypeDB::bind_method(_MD("_input"),&TouchScreenButton::_input); + + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture_pressed"),_SCS("get_texture_pressed")); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"bitmask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"),_SCS("set_bitmask"),_SCS("get_bitmask")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"passby_press"),_SCS("set_passby_press"),_SCS("is_passby_press_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::STRING,"action"),_SCS("set_action"),_SCS("get_action")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"visibility_mode",PROPERTY_HINT_ENUM,"Always,TouchScreen Only"),_SCS("set_visibility_mode"),_SCS("get_visibility_mode")); + + ADD_SIGNAL( MethodInfo("pressed" ) ); + ADD_SIGNAL( MethodInfo("release" ) ); + + + +} + +TouchScreenButton::TouchScreenButton() { + + finger_pressed=-1; + action_id=-1; + passby_press=false; + visibility=VISIBILITY_ALWAYS; +} diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h new file mode 100644 index 0000000000..7305fd29fe --- /dev/null +++ b/scene/2d/screen_button.h @@ -0,0 +1,95 @@ +/*************************************************************************/ +/* screen_button.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SCREEN_BUTTON_H +#define SCREEN_BUTTON_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/texture.h" +#include "scene/resources/bit_mask.h" + +class TouchScreenButton : public Node2D { + + OBJ_TYPE(TouchScreenButton,Node2D); +public: + + enum VisibilityMode { + VISIBILITY_ALWAYS, + VISIBILITY_TOUCHSCREEN_ONLY + }; + +private: + Ref<Texture> texture; + Ref<Texture> texture_pressed; + Ref<BitMap> bitmask; + + StringName action; + bool passby_press; + int finger_pressed; + int action_id; + + VisibilityMode visibility; + + void _input(const InputEvent& p_Event); + +protected: + + void _notification(int p_what); + static void _bind_methods(); +public: + + + void set_texture(const Ref<Texture>& p_texture); + Ref<Texture> get_texture() const; + + void set_texture_pressed(const Ref<Texture>& p_texture_pressed); + Ref<Texture> get_texture_pressed() const; + + void set_bitmask(const Ref<BitMap>& p_bitmask); + Ref<BitMap> get_bitmask() const; + + void set_action(const String& p_action); + String get_action() const; + + void set_passby_press(bool p_enable); + bool is_passby_press_enabled() const; + + void set_visibility_mode(VisibilityMode p_mode); + VisibilityMode get_visibility_mode() const; + + bool is_pressed() const; + + Rect2 get_item_rect() const; + + + TouchScreenButton(); +}; + +VARIANT_ENUM_CAST(TouchScreenButton::VisibilityMode); + +#endif // SCREEN_BUTTON_H diff --git a/scene/2d/sound_player_2d.cpp b/scene/2d/sound_player_2d.cpp new file mode 100644 index 0000000000..2fffef4e51 --- /dev/null +++ b/scene/2d/sound_player_2d.cpp @@ -0,0 +1,123 @@ +/*************************************************************************/ +/* sound_player_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "sound_player_2d.h" + +#include "servers/audio_server.h" + +#include "servers/spatial_sound_2d_server.h" +#include "scene/resources/surface_tool.h" + + +void SoundPlayer2D::_notification(int p_what) { + + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + //find the sound space + + source_rid = SpatialSound2DServer::get_singleton()->source_create(get_world_2d()->get_sound_space()); + + for(int i=0;i<PARAM_MAX;i++) + set_param(Param(i),params[i]); + + SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform()); + + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform()); + + } break; + case NOTIFICATION_EXIT_SCENE: { + + if (source_rid.is_valid()) + SpatialSound2DServer::get_singleton()->free(source_rid); + + } break; + } + +} + + +void SoundPlayer2D::set_param( Param p_param, float p_value) { + + ERR_FAIL_INDEX(p_param,PARAM_MAX); + params[p_param]=p_value; + if (source_rid.is_valid()) + SpatialSound2DServer::get_singleton()->source_set_param(source_rid,(SpatialSound2DServer::SourceParam)p_param,p_value); + +} + +float SoundPlayer2D::get_param( Param p_param) const { + + ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0); + return params[p_param]; + +} + + +void SoundPlayer2D::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_param","param","value"),&SoundPlayer2D::set_param); + ObjectTypeDB::bind_method(_MD("get_param","param"),&SoundPlayer2D::get_param); + + BIND_CONSTANT( PARAM_VOLUME_DB ); + BIND_CONSTANT( PARAM_PITCH_SCALE ); + BIND_CONSTANT( PARAM_ATTENUATION_MIN_DISTANCE ); + BIND_CONSTANT( PARAM_ATTENUATION_MAX_DISTANCE ); + BIND_CONSTANT( PARAM_ATTENUATION_DISTANCE_EXP ); + BIND_CONSTANT( PARAM_MAX ); + + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/volume_db",PROPERTY_HINT_RANGE, "-80,24,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_VOLUME_DB); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/pitch_scale",PROPERTY_HINT_RANGE, "0.001,32,0.001"),_SCS("set_param"),_SCS("get_param"),PARAM_PITCH_SCALE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/min_distance",PROPERTY_HINT_EXP_RANGE, "16,16384,1"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_MIN_DISTANCE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/max_distance",PROPERTY_HINT_EXP_RANGE, "16,16384,1"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_MAX_DISTANCE); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation/distance_exp",PROPERTY_HINT_EXP_EASING, "attenuation"),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION_DISTANCE_EXP); + +} + + +SoundPlayer2D::SoundPlayer2D() { + + params[PARAM_VOLUME_DB]=0.0; + params[PARAM_PITCH_SCALE]=1.0; + params[PARAM_ATTENUATION_MIN_DISTANCE]=1; + params[PARAM_ATTENUATION_MAX_DISTANCE]=2048; + params[PARAM_ATTENUATION_DISTANCE_EXP]=1.0; //linear (and not really good) + + +} + +SoundPlayer2D::~SoundPlayer2D() { + + +} diff --git a/scene/2d/sound_player_2d.h b/scene/2d/sound_player_2d.h new file mode 100644 index 0000000000..9578c6b323 --- /dev/null +++ b/scene/2d/sound_player_2d.h @@ -0,0 +1,82 @@ +/*************************************************************************/ +/* sound_player_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SOUND_PLAYER_2D_H +#define SOUND_PLAYER_2D_H + + +#include "scene/2d/node_2d.h" +#include "scene/resources/sample_library.h" +#include "servers/spatial_sound_2d_server.h" +#include "scene/main/viewport.h" + +class SoundPlayer2D : public Node2D { + + OBJ_TYPE(SoundPlayer2D,Node2D); +public: + + + enum Param { + + PARAM_VOLUME_DB=SpatialSound2DServer::SOURCE_PARAM_VOLUME_DB, + PARAM_PITCH_SCALE=SpatialSound2DServer::SOURCE_PARAM_PITCH_SCALE, + PARAM_ATTENUATION_MIN_DISTANCE=SpatialSound2DServer::SOURCE_PARAM_ATTENUATION_MIN_DISTANCE, + PARAM_ATTENUATION_MAX_DISTANCE=SpatialSound2DServer::SOURCE_PARAM_ATTENUATION_MAX_DISTANCE, + PARAM_ATTENUATION_DISTANCE_EXP=SpatialSound2DServer::SOURCE_PARAM_ATTENUATION_DISTANCE_EXP, + PARAM_MAX=SpatialSound2DServer::SOURCE_PARAM_MAX + }; + +private: + + float params[PARAM_MAX]; + RID source_rid; + + +protected: + + _FORCE_INLINE_ RID get_source_rid() const { return source_rid; } + + void _notification(int p_what); + + static void _bind_methods(); + +public: + + void set_param( Param p_param, float p_value); + float get_param( Param p_param) const; + + + SoundPlayer2D(); + ~SoundPlayer2D(); + + +}; + +VARIANT_ENUM_CAST(SoundPlayer2D::Param ); + +#endif // SOUND_PLAYER_2D_H diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp new file mode 100644 index 0000000000..0265ec4df2 --- /dev/null +++ b/scene/2d/sprite.cpp @@ -0,0 +1,337 @@ +/*************************************************************************/ +/* sprite.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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" +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; + */ + + Size2i s; + Rect2i src_rect; + + if (region) { + + s=region_rect.size; + src_rect=region_rect; + } else { + s = texture->get_size(); + s=s/Size2i(hframes,vframes); + + src_rect.size=s; + src_rect.pos.x+=(frame%hframes)*s.x; + src_rect.pos.y+=(frame/hframes)*s.y; + + } + + Point2i ofs=offset; + if (centered) + ofs-=s/2; + + Rect2i 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; + if (texture.is_valid()) { + texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update); + } + texture=p_texture; + if (texture.is_valid()) { + texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites + texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update); + } + update(); + 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(); +} +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) { + + bool changed=region_rect!=p_region_rect; + region_rect=p_region_rect; + if (region && changed) { + update(); + item_rect_changed(); + } +} + +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; +} + +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); + } + + Point2i ofs=offset; + if (centered) + ofs-=s/2; + + if (s==Size2(0,0)) + s=Size2(1,1); + + return Rect2(ofs,s); +} + + +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_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); + ADD_PROPERTY( 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); + + +} diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h new file mode 100644 index 0000000000..42f737fa91 --- /dev/null +++ b/scene/2d/sprite.h @@ -0,0 +1,108 @@ +/*************************************************************************/ +/* sprite.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef SPRITE_H +#define SPRITE_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/texture.h" + + +class Sprite : public Node2D { + + OBJ_TYPE( Sprite, Node2D ); + + Ref<Texture> texture; + + bool centered; + Point2 offset; + + bool hflip; + bool vflip; + bool region; + Rect2 region_rect; + + int frame; + + int vframes; + int hframes; + + Color modulate; + + +protected: + + void _notification(int p_what); + + static void _bind_methods();; + +public: + + virtual void edit_set_pivot(const Point2& p_pivot); + virtual Point2 edit_get_pivot() const; + virtual bool edit_has_pivot() const; + + void set_texture(const Ref<Texture>& p_texture); + Ref<Texture> get_texture() const; + + void set_centered(bool p_center); + bool is_centered() const; + + void set_offset(const Point2& p_offset); + Point2 get_offset() const; + + void set_flip_h(bool p_flip); + bool is_flipped_h() const; + + void set_flip_v(bool p_flip); + bool is_flipped_v() const; + + void set_region(bool p_region); + bool is_region() const; + + void set_region_rect(const Rect2& p_region_rect); + Rect2 get_region_rect() const; + + void set_frame(int p_frame); + int get_frame() const; + + void set_vframes(int p_amount); + int get_vframes() const; + + void set_hframes(int p_amount); + int get_hframes() const; + + void set_modulate(const Color& p_color); + Color get_modulate() const; + + virtual Rect2 get_item_rect() const; + + Sprite(); +}; + +#endif // SPRITE_H diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp new file mode 100644 index 0000000000..26efa99a88 --- /dev/null +++ b/scene/2d/tile_map.cpp @@ -0,0 +1,592 @@ +/*************************************************************************/ +/* tile_map.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "tile_map.h" +#include "io/marshalls.h" +#include "servers/physics_2d_server.h" +void TileMap::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_SCENE: { + + pending_update=true; + _update_dirty_quadrants(); + RID space = get_world_2d()->get_space(); + _update_quadrant_transform(); + _update_quadrant_space(space); + + + } break; + case NOTIFICATION_EXIT_SCENE: { + + _update_quadrant_space(RID()); + + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + //move stuff + _update_quadrant_transform(); + + } break; + } +} + +void TileMap::_update_quadrant_space(const RID& p_space) { + + for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { + + Quadrant &q=E->get(); + Physics2DServer::get_singleton()->body_set_space(q.static_body,p_space); + } +} + +void TileMap::_update_quadrant_transform() { + + if (!is_inside_scene()) + return; + + Matrix32 global_transform = get_global_transform(); + + for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { + + Quadrant &q=E->get(); + Matrix32 xform; + xform.set_origin( q.pos ); + xform = global_transform * xform; + Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform); + } +} + +void TileMap::set_tileset(const Ref<TileSet>& p_tileset) { + + if (tile_set.is_valid()) + tile_set->disconnect("changed",this,"_recreate_quadrants"); + + _clear_quadrants(); + tile_set=p_tileset; + + if (tile_set.is_valid()) + tile_set->connect("changed",this,"_recreate_quadrants"); + else + clear(); + + _recreate_quadrants(); + +} + +Ref<TileSet> TileMap::get_tileset() const { + + return tile_set; +} + +void TileMap::set_cell_size(int p_size) { + + ERR_FAIL_COND(p_size<1); + + _clear_quadrants(); + cell_size=p_size; + _recreate_quadrants(); + + +} +int TileMap::get_cell_size() const { + + return cell_size; +} +void TileMap::set_quadrant_size(int p_size) { + + ERR_FAIL_COND(p_size<1); + + _clear_quadrants(); + quadrant_size=p_size; + _recreate_quadrants(); + +} +int TileMap::get_quadrant_size() const { + + return quadrant_size; +} + +void TileMap::set_center_x(bool p_enable) { + + center_x=p_enable; + _recreate_quadrants(); + +} +bool TileMap::get_center_x() const { + + return center_x; +} +void TileMap::set_center_y(bool p_enable) { + + center_y=p_enable; + _recreate_quadrants(); + +} +bool TileMap::get_center_y() const { + + return center_y; +} + +void TileMap::_update_dirty_quadrants() { + + if (!pending_update) + return; + if (!is_inside_scene()) + return; + if (!tile_set.is_valid()) + return; + + VisualServer *vs = VisualServer::get_singleton(); + Physics2DServer *ps = Physics2DServer::get_singleton(); + + while (dirty_quadrant_list.first()) { + + Quadrant &q = *dirty_quadrant_list.first()->self(); + + vs->canvas_item_clear(q.canvas_item); + ps->body_clear_shapes(q.static_body); + + for(int i=0;i<q.cells.size();i++) { + + Map<PosKey,Cell>::Element *E=tile_map.find( q.cells[i] ); + Cell &c=E->get(); + //moment of truth + if (!tile_set->has_tile(c.id)) + continue; + Ref<Texture> tex = tile_set->tile_get_texture(c.id); + Vector2 tile_ofs = tile_set->tile_get_offset(c.id); + + Vector2 offset = Point2( E->key().x, E->key().y )*cell_size - q.pos; + + if (!tex.is_valid()) + continue; + + + Rect2 r = tile_set->tile_get_region(c.id); + Size2 s = tex->get_size(); + + if (r==Rect2()) + s = tex->get_size(); + else { + s = r.size; + r.pos.x+=fp_adjust; + r.pos.y+=fp_adjust; + r.size.x-=fp_adjust*2.0; + r.size.y-=fp_adjust*2.0; + } + + Rect2 rect; + rect.pos=offset.floor(); + rect.size=s; + + rect.size.x+=fp_adjust; + rect.size.y+=fp_adjust; + + if (c.flip_h) + rect.size.x=-rect.size.x; + if (c.flip_v) + rect.size.y=-rect.size.y; + + + if (r==Rect2()) { + + tex->draw_rect(q.canvas_item,rect); + } else { + + tex->draw_rect_region(q.canvas_item,rect,r); + } + + Vector< Ref<Shape2D> > shapes = tile_set->tile_get_shapes(c.id); + + + for(int i=0;i<shapes.size();i++) { + + Ref<Shape2D> shape = shapes[i]; + if (shape.is_valid()) { + + Matrix32 xform; + xform.set_origin(offset.floor()); + if (c.flip_h) { + xform.elements[0]=-xform.elements[0]; + xform.elements[2].x+=s.x; + } + if (c.flip_v) { + xform.elements[1]=-xform.elements[1]; + xform.elements[2].y+=s.y; + } + + ps->body_add_shape(q.static_body,shape->get_rid(),xform); + } + } + } + + dirty_quadrant_list.remove( dirty_quadrant_list.first() ); + } + + + + pending_update=false; + + _recompute_rect_cache(); + +} + +void TileMap::_recompute_rect_cache() { + + +#ifdef DEBUG_ENABLED + + if (!rect_cache_dirty) + return; + + Rect2 r_total; + for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { + + + Rect2 r( Point2(E->key().x, E->key().y)*cell_size*quadrant_size, Size2(1,1)*cell_size*quadrant_size ); + if (E==quadrant_map.front()) + r_total=r; + else + r_total=r_total.merge(r); + + } + if (r_total==Rect2()) { + rect_cache=Rect2(-10,-10,20,20); + } else { + rect_cache=r_total; + } + + item_rect_changed(); + + rect_cache_dirty=false; +#endif + + +} + +Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey& p_qk) { + + Matrix32 xform; + xform.set_origin(Point2(p_qk.x,p_qk.y)*quadrant_size*cell_size); + Quadrant q; + q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); + VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() ); + VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform ); + q.static_body=Physics2DServer::get_singleton()->body_create(Physics2DServer::BODY_MODE_STATIC); + if (is_inside_scene()) { + xform = get_global_transform() * xform; + RID space = get_world_2d()->get_space(); + Physics2DServer::get_singleton()->body_set_space(q.static_body,space); + } + + Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform); + q.pos=Vector2(p_qk.x,p_qk.y)*quadrant_size*cell_size; + + rect_cache_dirty=true; + return quadrant_map.insert(p_qk,q); +} + +void TileMap::_erase_quadrant(Map<PosKey,Quadrant>::Element *Q) { + + Quadrant &q=Q->get(); + Physics2DServer::get_singleton()->free(q.static_body); + VisualServer::get_singleton()->free(q.canvas_item); + if (q.dirty_list.in_list()) + dirty_quadrant_list.remove(&q.dirty_list); + + quadrant_map.erase(Q); + rect_cache_dirty=true; +} + +void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) { + + Quadrant &q=Q->get(); + if (!q.dirty_list.in_list()) + dirty_quadrant_list.add(&q.dirty_list); + + if (pending_update) + return; + pending_update=true; + if (!is_inside_scene()) + return; + call_deferred("_update_dirty_quadrants"); +} + + +void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y) { + + PosKey pk(p_x,p_y); + + Map<PosKey,Cell>::Element *E=tile_map.find(pk); + if (!E && p_tile==INVALID_CELL) + return; //nothing to do + + PosKey qk(p_x/quadrant_size,p_y/quadrant_size); + if (p_tile==INVALID_CELL) { + //erase existing + tile_map.erase(pk); + Map<PosKey,Quadrant>::Element *Q = quadrant_map.find(qk); + ERR_FAIL_COND(!Q); + Quadrant &q=Q->get(); + q.cells.erase(pk); + if (q.cells.size()==0) + _erase_quadrant(Q); + else + _make_quadrant_dirty(Q); + + return; + } + + Map<PosKey,Quadrant>::Element *Q = quadrant_map.find(qk); + + if (!E) { + E=tile_map.insert(pk,Cell()); + if (!Q) + Q=_create_quadrant(qk); + Quadrant &q=Q->get(); + q.cells.insert(pk); + } else { + ERR_FAIL_COND(!Q); // quadrant should exist... + + if (E->get().id==p_tile && E->get().flip_h==p_flip_x && E->get().flip_v==p_flip_y) + return; //nothing changed + + } + + + Cell &c = E->get(); + + c.id=p_tile; + c.flip_h=p_flip_x; + c.flip_v=p_flip_y; + + _make_quadrant_dirty(Q); + +} + +int TileMap::get_cell(int p_x,int p_y) const { + + PosKey pk(p_x,p_y); + + const Map<PosKey,Cell>::Element *E=tile_map.find(pk); + + if (!E) + return INVALID_CELL; + + return E->get().id; + +} +bool TileMap::is_cell_x_flipped(int p_x,int p_y) const { + + PosKey pk(p_x,p_y); + + const Map<PosKey,Cell>::Element *E=tile_map.find(pk); + + if (!E) + return false; + + return E->get().flip_h; +} +bool TileMap::is_cell_y_flipped(int p_x,int p_y) const { + + PosKey pk(p_x,p_y); + + const Map<PosKey,Cell>::Element *E=tile_map.find(pk); + + if (!E) + return false; + + return E->get().flip_v; +} + + +void TileMap::_recreate_quadrants() { + + _clear_quadrants(); + + for (Map<PosKey,Cell>::Element *E=tile_map.front();E;E=E->next()) { + + PosKey qk(E->key().x/quadrant_size,E->key().y/quadrant_size); + + Map<PosKey,Quadrant>::Element *Q=quadrant_map.find(qk); + if (!Q) { + Q=_create_quadrant(qk); + dirty_quadrant_list.add(&Q->get().dirty_list); + } + + Q->get().cells.insert(E->key()); + + } +} + +void TileMap::_clear_quadrants() { + + while (quadrant_map.size()) { + _erase_quadrant( quadrant_map.front() ); + } +} + +void TileMap::clear() { + + _clear_quadrants(); + tile_map.clear(); +} + +void TileMap::_set_tile_data(const DVector<int>& p_data) { + + int c=p_data.size(); + DVector<int>::Read r = p_data.read(); + + + for(int i=0;i<c;i+=2) { + + const uint8_t *ptr=(const uint8_t*)&r[i]; + uint8_t local[8]; + for(int j=0;j<8;j++) + local[j]=ptr[j]; + +#ifdef BIG_ENDIAN_ENABLED + + + SWAP(local[0],local[3]); + SWAP(local[1],local[2]); + SWAP(local[4],local[7]); + SWAP(local[5],local[6]); +#endif + int x = decode_uint16(&local[0]); + int y = decode_uint16(&local[2]); + uint32_t v = decode_uint32(&local[4]); + bool flip_h = v&(1<<29); + bool flip_v = v&(1<<30); + v&=(1<<29)-1; + +// if (x<-20 || y <-20 || x>4000 || y>4000) +// continue; + set_cell(x,y,v,flip_h,flip_v); + } + +} + +DVector<int> TileMap::_get_tile_data() const { + + DVector<int> data; + data.resize(tile_map.size()*2); + DVector<int>::Write w = data.write(); + + int idx=0; + for(const Map<PosKey,Cell>::Element *E=tile_map.front();E;E=E->next()) { + + uint8_t *ptr = (uint8_t*)&w[idx]; + encode_uint16(E->key().x,&ptr[0]); + encode_uint16(E->key().y,&ptr[2]); + uint32_t val = E->get().id; + if (E->get().flip_h) + val|=(1<<29); + if (E->get().flip_v) + val|=(1<<30); + + encode_uint32(val,&ptr[4]); + idx+=2; + } + + + w = DVector<int>::Write(); + + return data; + +} + +Rect2 TileMap::get_item_rect() const { + + const_cast<TileMap*>(this)->_update_dirty_quadrants(); + return rect_cache; +} + +void TileMap::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_tileset","tileset:TileSet"),&TileMap::set_tileset); + ObjectTypeDB::bind_method(_MD("get_tileset:TileSet"),&TileMap::get_tileset); + + + ObjectTypeDB::bind_method(_MD("set_cell_size","size"),&TileMap::set_cell_size); + ObjectTypeDB::bind_method(_MD("get_cell_size"),&TileMap::get_cell_size); + + ObjectTypeDB::bind_method(_MD("set_quadrant_size","size"),&TileMap::set_quadrant_size); + ObjectTypeDB::bind_method(_MD("get_quadrant_size"),&TileMap::get_quadrant_size); + + ObjectTypeDB::bind_method(_MD("set_center_x","enable"),&TileMap::set_center_x); + ObjectTypeDB::bind_method(_MD("get_center_x"),&TileMap::get_center_x); + + ObjectTypeDB::bind_method(_MD("set_center_y","enable"),&TileMap::set_center_y); + ObjectTypeDB::bind_method(_MD("get_center_y"),&TileMap::get_center_y); + + + ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell); + ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped); + ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped); + + ObjectTypeDB::bind_method(_MD("clear"),&TileMap::clear); + + ObjectTypeDB::bind_method(_MD("_clear_quadrants"),&TileMap::_clear_quadrants); + ObjectTypeDB::bind_method(_MD("_recreate_quadrants"),&TileMap::_recreate_quadrants); + ObjectTypeDB::bind_method(_MD("_update_dirty_quadrants"),&TileMap::_update_dirty_quadrants); + + ObjectTypeDB::bind_method(_MD("_set_tile_data"),&TileMap::_set_tile_data); + ObjectTypeDB::bind_method(_MD("_get_tile_data"),&TileMap::_get_tile_data); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"cell_size",PROPERTY_HINT_RANGE,"1,8192,1"),_SCS("set_cell_size"),_SCS("get_cell_size")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size")); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_set",PROPERTY_HINT_RESOURCE_TYPE,"TileSet"),_SCS("set_tileset"),_SCS("get_tileset")); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data")); + + BIND_CONSTANT( INVALID_CELL ); +} + +TileMap::TileMap() { + + + + rect_cache_dirty=true; + pending_update=false; + quadrant_size=16; + cell_size=64; + center_x=false; + center_y=false; + + fp_adjust=0.4; + fp_adjust=0.4; +} + +TileMap::~TileMap() { + + clear(); +} diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h new file mode 100644 index 0000000000..a2414382c6 --- /dev/null +++ b/scene/2d/tile_map.h @@ -0,0 +1,154 @@ +/*************************************************************************/ +/* tile_map.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef TILE_MAP_H +#define TILE_MAP_H + +#include "scene/2d/node_2d.h" +#include "scene/resources/tile_set.h" +#include "self_list.h" +#include "vset.h" + +class TileMap : public Node2D { + + OBJ_TYPE( TileMap, Node2D ); + + + Ref<TileSet> tile_set; + int cell_size; + int quadrant_size; + bool center_x,center_y; + + union PosKey { + + struct { + int16_t x; + int16_t y; + }; + + uint32_t key; + bool operator<(const PosKey& pk) const { return key<pk.key; } + + PosKey(int16_t p_x, int16_t p_y) { x=p_x; y=p_y; } + PosKey() { key=0; } + + }; + + + union Cell { + + struct { + int32_t id:24; + bool flip_h:1; + bool flip_v:1; + }; + + uint32_t _u32t; + Cell() { _u32t=0; } + }; + + + Map<PosKey,Cell> tile_map; + struct Quadrant { + + Vector2 pos; + RID canvas_item; + RID static_body; + + SelfList<Quadrant> dirty_list; + + VSet<PosKey> cells; + + void operator=(const Quadrant& q) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells; } + Quadrant(const Quadrant& q) : dirty_list(this) { pos=q.pos; canvas_item=q.canvas_item; static_body=q.static_body; cells=q.cells;} + Quadrant() : dirty_list(this) {} + }; + + Map<PosKey,Quadrant> quadrant_map; + + SelfList<Quadrant>::List dirty_quadrant_list; + + bool pending_update; + + Rect2 rect_cache; + bool rect_cache_dirty; + float fp_adjust; + + + Map<PosKey,Quadrant>::Element *_create_quadrant(const PosKey& p_qk); + void _erase_quadrant(Map<PosKey,Quadrant>::Element *Q); + void _make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q); + void _recreate_quadrants(); + void _clear_quadrants(); + void _update_dirty_quadrants(); + void _update_quadrant_space(const RID& p_space); + void _update_quadrant_transform(); + void _recompute_rect_cache(); + + void _set_tile_data(const DVector<int>& p_data); + DVector<int> _get_tile_data() const; +protected: + + + void _notification(int p_what); + static void _bind_methods(); + +public: + + enum { + INVALID_CELL=-1 + }; + + void set_tileset(const Ref<TileSet>& p_tileset); + Ref<TileSet> get_tileset() const; + + void set_cell_size(int p_size); + int get_cell_size() const; + + void set_quadrant_size(int p_size); + int get_quadrant_size() const; + + void set_center_x(bool p_enable); + bool get_center_x() const; + void set_center_y(bool p_enable); + bool get_center_y() const; + + void set_cell(int p_x,int p_y,int p_tile,bool p_flip_x=false,bool p_flip_y=false); + int get_cell(int p_x,int p_y) const; + bool is_cell_x_flipped(int p_x,int p_y) const; + bool is_cell_y_flipped(int p_x,int p_y) const; + + Rect2 get_item_rect() const; + + void clear(); + + TileMap(); + ~TileMap(); +}; + +#endif // TILE_MAP_H diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp new file mode 100644 index 0000000000..323d02df4b --- /dev/null +++ b/scene/2d/visibility_notifier_2d.cpp @@ -0,0 +1,322 @@ +/*************************************************************************/ +/* visibility_notifier_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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 "visibility_notifier_2d.h" + +#include "scene/scene_string_names.h" +#include "scene/2d/physics_body_2d.h" +#include "scene/animation/animation_player.h" +#include "scene/scene_string_names.h" + +void VisibilityNotifier2D::_enter_viewport(Viewport* p_viewport) { + + ERR_FAIL_COND(viewports.has(p_viewport)); + viewports.insert(p_viewport); + if (viewports.size()==1) { + emit_signal(SceneStringNames::get_singleton()->enter_screen); + _screen_enter(); + + + } + emit_signal(SceneStringNames::get_singleton()->enter_viewport,p_viewport); + +} + +void VisibilityNotifier2D::_exit_viewport(Viewport* p_viewport){ + + ERR_FAIL_COND(!viewports.has(p_viewport)); + viewports.erase(p_viewport); + + emit_signal(SceneStringNames::get_singleton()->exit_viewport,p_viewport); + if (viewports.size()==0) { + emit_signal(SceneStringNames::get_singleton()->exit_screen); + + _screen_exit(); + } +} + + +void VisibilityNotifier2D::set_rect(const Rect2& p_rect){ + + rect=p_rect; + if (is_inside_scene()) + get_world_2d()->_update_notifier(this,get_global_transform().xform(rect)); + + _change_notify("rect"); +} + +Rect2 VisibilityNotifier2D::get_item_rect() const { + + return rect; +} + +Rect2 VisibilityNotifier2D::get_rect() const{ + + return rect; +} + + +void VisibilityNotifier2D::_notification(int p_what) { + + + switch(p_what) { + case NOTIFICATION_ENTER_SCENE: { + + //get_world_2d()-> + get_world_2d()->_register_notifier(this,get_global_transform().xform(rect)); + } break; + case NOTIFICATION_TRANSFORM_CHANGED: { + + //get_world_2d()-> + get_world_2d()->_update_notifier(this,get_global_transform().xform(rect)); + } break; + case NOTIFICATION_DRAW: { + + if (get_scene()->is_editor_hint()) { + + draw_rect(rect,Color(1,0.5,1,0.2)); + } + } break; + case NOTIFICATION_EXIT_SCENE: { + + get_world_2d()->_remove_notifier(this); + } break; + } +} + +bool VisibilityNotifier2D::is_on_screen() const { + + return viewports.size()>0; +} + +void VisibilityNotifier2D::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_rect","rect"),&VisibilityNotifier2D::set_rect); + ObjectTypeDB::bind_method(_MD("get_rect"),&VisibilityNotifier2D::get_rect); + ObjectTypeDB::bind_method(_MD("is_on_screen"),&VisibilityNotifier2D::is_on_screen); + + ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"),_SCS("set_rect"),_SCS("get_rect")); + + ADD_SIGNAL( MethodInfo("enter_viewport",PropertyInfo(Variant::OBJECT,"viewport",PROPERTY_HINT_RESOURCE_TYPE,"Viewport")) ); + ADD_SIGNAL( MethodInfo("exit_viewport",PropertyInfo(Variant::OBJECT,"viewport",PROPERTY_HINT_RESOURCE_TYPE,"Viewport")) ); + ADD_SIGNAL( MethodInfo("enter_screen")); + ADD_SIGNAL( MethodInfo("exit_screen")); +} + + +VisibilityNotifier2D::VisibilityNotifier2D() { + + rect=Rect2(-10,-10,20,20); +} + + + + + +////////////////////////////////////// + + +void VisibilityEnabler2D::_screen_enter() { + + + for(Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) { + + _change_node_state(E->key(),true); + } + + visible=true; +} + +void VisibilityEnabler2D::_screen_exit(){ + + for(Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) { + + _change_node_state(E->key(),false); + } + + visible=false; +} + +void VisibilityEnabler2D::_find_nodes(Node* p_node) { + + + bool add=false; + Variant meta; + + if (enabler[ENABLER_FREEZE_BODIES]) { + + RigidBody2D *rb2d = p_node->cast_to<RigidBody2D>(); + if (rb2d && ((rb2d->get_mode()==RigidBody2D::MODE_CHARACTER || (rb2d->get_mode()==RigidBody2D::MODE_RIGID && !rb2d->is_able_to_sleep())))) { + + + add=true; + meta=rb2d->get_mode(); + } + } + + if (enabler[ENABLER_PAUSE_ANIMATIONS]) { + + AnimationPlayer *ap = p_node->cast_to<AnimationPlayer>(); + if (ap) { + add=true; + } + + } + + if (add) { + + p_node->connect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); + nodes[p_node]=meta; + _change_node_state(p_node,false); + } + + for(int i=0;i<p_node->get_child_count();i++) { + Node *c = p_node->get_child(i); + if (c->get_filename()!=String()) + continue; //skip, instance + + _find_nodes(c); + } + +} + +void VisibilityEnabler2D::_notification(int p_what){ + + if (p_what==NOTIFICATION_ENTER_SCENE) { + + if (get_scene()->is_editor_hint()) + return; + + + Node *from = this; + //find where current scene starts + while(from->get_parent() && from->get_filename()==String()) + from=from->get_parent(); + + _find_nodes(from); + + } + + if (p_what==NOTIFICATION_EXIT_SCENE) { + + if (get_scene()->is_editor_hint()) + return; + + + Node *from = this; + //find where current scene starts + + for (Map<Node*,Variant>::Element *E=nodes.front();E;E=E->next()) { + + if (!visible) + _change_node_state(E->key(),true); + E->key()->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + } + + nodes.clear(); + + } +} + +void VisibilityEnabler2D::_change_node_state(Node* p_node,bool p_enabled) { + + ERR_FAIL_COND(!nodes.has(p_node)); + + { + RigidBody2D *rb = p_node->cast_to<RigidBody2D>(); + if (rb) { + + if (p_enabled) { + RigidBody2D::Mode mode = RigidBody2D::Mode(nodes[p_node].operator int()); + //rb->set_mode(mode); + rb->set_active(true); + } else { + //rb->set_mode(RigidBody2D::MODE_STATIC); + rb->set_active(false); + } + } + } + + { + AnimationPlayer *ap=p_node->cast_to<AnimationPlayer>(); + + if (ap) { + + ap->set_active(p_enabled); + } + } + +} + + +void VisibilityEnabler2D::_node_removed(Node* p_node) { + + if (!visible) + _change_node_state(p_node,true); + //changed to one shot, not needed + //p_node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + nodes.erase(p_node); + +} + +void VisibilityEnabler2D::_bind_methods(){ + + ObjectTypeDB::bind_method(_MD("set_enabler","enabler","enabled"),&VisibilityEnabler2D::set_enabler); + ObjectTypeDB::bind_method(_MD("is_enabler_enabled","enabler"),&VisibilityEnabler2D::is_enabler_enabled); + ObjectTypeDB::bind_method(_MD("_node_removed"),&VisibilityEnabler2D::_node_removed); + + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animations"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS ); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/freeze_bodies"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES); + + BIND_CONSTANT( ENABLER_FREEZE_BODIES ); + BIND_CONSTANT( ENABLER_PAUSE_ANIMATIONS ); + BIND_CONSTANT( ENABLER_MAX); +} + +void VisibilityEnabler2D::set_enabler(Enabler p_enabler,bool p_enable){ + + ERR_FAIL_INDEX(p_enabler,ENABLER_MAX); + enabler[p_enabler]=p_enable; + +} +bool VisibilityEnabler2D::is_enabler_enabled(Enabler p_enabler) const{ + + ERR_FAIL_INDEX_V(p_enabler,ENABLER_MAX,false); + return enabler[p_enabler]; + +} + +VisibilityEnabler2D::VisibilityEnabler2D() { + + for(int i=0;i<ENABLER_MAX;i++) + enabler[i]=true; + + visible=false; + +} + diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h new file mode 100644 index 0000000000..cdf52ecb27 --- /dev/null +++ b/scene/2d/visibility_notifier_2d.h @@ -0,0 +1,109 @@ +/*************************************************************************/ +/* visibility_notifier_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2014 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. */ +/*************************************************************************/ +#ifndef VISIBILITY_NOTIFIER_2D_H +#define VISIBILITY_NOTIFIER_2D_H + +#include "scene/2d/node_2d.h" + +class Viewport; +class VisibilityNotifier2D : public Node2D { + + OBJ_TYPE(VisibilityNotifier2D,Node2D); + + Set<Viewport*> viewports; + + Rect2 rect; + +protected: +friend class SpatialIndexer2D; + + void _enter_viewport(Viewport* p_viewport); + void _exit_viewport(Viewport* p_viewport); + + + virtual void _screen_enter() {} + virtual void _screen_exit() {} + + void _notification(int p_what); + static void _bind_methods(); +public: + + void set_rect(const Rect2& p_rect); + Rect2 get_rect() const; + + bool is_on_screen() const; + + virtual Rect2 get_item_rect() const; + + VisibilityNotifier2D(); +}; + + +class VisibilityEnabler2D : public VisibilityNotifier2D { + + OBJ_TYPE(VisibilityEnabler2D,VisibilityNotifier2D); +public: + + enum Enabler { + ENABLER_PAUSE_ANIMATIONS, + ENABLER_FREEZE_BODIES, + ENABLER_MAX + }; + +protected: + + virtual void _screen_enter(); + virtual void _screen_exit(); + + bool visible; + + void _find_nodes(Node* p_node); + + Map<Node*,Variant> nodes; + void _node_removed(Node* p_node); + bool enabler[ENABLER_MAX]; + + void _change_node_state(Node* p_node,bool p_enabled); + + void _notification(int p_what); + static void _bind_methods(); + +public: + + void set_enabler(Enabler p_enabler,bool p_enable); + bool is_enabler_enabled(Enabler p_enabler) const; + + VisibilityEnabler2D(); + +}; + +VARIANT_ENUM_CAST(VisibilityEnabler2D::Enabler); + + +#endif // VISIBILITY_NOTIFIER_2D_H |