Ver Fonte

Merge branch 'master' of github.com:okamstudio/godot into development

James McLean há 10 anos atrás
pai
commit
86c87ee66a

+ 0 - 7
core/os/memory.cpp

@@ -112,13 +112,6 @@ size_t Memory::get_dynamic_mem_usage() {
 	return MemoryPoolDynamic::get_singleton()->get_total_usage();
 }
 
-void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_description) {
-
-	void *failptr=0;
-	ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */
-
-	return p_pointer;
-}
 
 
 

+ 12 - 5
core/os/memory.h

@@ -236,11 +236,11 @@ void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_de
 #endif
 
 
-_FORCE_INLINE_ void postinitialize_handler(void *) {}
+_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
 
 
 template<class T>
-_FORCE_INLINE_ T *_post_initialize(T *p_obj) {
+_ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
 	
 	postinitialize_handler(p_obj);
 	return p_obj;
@@ -249,19 +249,26 @@ _FORCE_INLINE_ T *_post_initialize(T *p_obj) {
 #ifdef DEBUG_MEMORY_ENABLED
 
 #define memnew(m_class) _post_initialize(new(__FILE__":"__STR(__LINE__)", memnew type: "__STR(m_class)) m_class)
-#define memnew_placement(m_placement,m_class) _post_initialize(new(m_placement,sizeof(m_class),__FILE__":"__STR(__LINE__)", type: "__STR(m_class)) m_class)
 
 #else
 
 #define memnew(m_class) _post_initialize(new("") m_class)
-#define memnew_placement(m_placement,m_class) _post_initialize(new(m_placement,sizeof(m_class),"") m_class)
 
 #endif
 
+_ALWAYS_INLINE_ void * operator new(size_t p_size,void *p_pointer,size_t check, const char *p_description) {
+//	void *failptr=0;
+//	ERR_FAIL_COND_V( check < p_size , failptr); /** bug, or strange compiler, most likely */
+
+	return p_pointer;
+}
+
+
 #define memnew_allocator(m_class,m_allocator) _post_initialize(new(m_allocator::alloc) m_class)
+#define memnew_placement(m_placement,m_class) _post_initialize(new(m_placement,sizeof(m_class),"") m_class)
 
 
-_FORCE_INLINE_ bool predelete_handler(void *) { return true; }
+_ALWAYS_INLINE_ bool predelete_handler(void *) { return true; }
 
 template<class T>
 void memdelete(T *p_class) {

+ 1 - 1
drivers/gles2/rasterizer_gles2.cpp

@@ -4402,7 +4402,7 @@ void RasterizerGLES2::set_camera(const Transform& p_world,const CameraMatrix& p_
 	}
 	camera_transform_inverse=camera_transform.inverse();
 	camera_projection=p_projection;
-	camera_plane = Plane( camera_transform.origin, camera_transform.basis.get_axis(2) );
+	camera_plane = Plane( camera_transform.origin, -camera_transform.basis.get_axis(2) );
 	camera_z_near=camera_projection.get_z_near();
 	camera_z_far=camera_projection.get_z_far();
 	camera_projection.get_viewport_size(camera_vp_size.x,camera_vp_size.y);

+ 2 - 2
platform/x11/detect.py

@@ -111,9 +111,9 @@ def configure(env):
 	if (env["target"]=="release"):
 
 		if (env["debug_release"]=="yes"):
-			env.Append(CCFLAGS=['-g2','-fomit-frame-pointer'])
+			env.Append(CCFLAGS=['-g2'])
 		else:
-			env.Append(CCFLAGS=['-O2','-ffast-math','-fomit-frame-pointer'])
+			env.Append(CCFLAGS=['-O3','-ffast-math'])
 
 	elif (env["target"]=="release_debug"):
 

+ 3 - 3
scene/2d/animated_sprite.cpp

@@ -149,11 +149,11 @@ void AnimatedSprite::_notification(int p_what) {
 
 			Size2i s;
 			s = texture->get_size();
-			Point2i ofs=offset;
+			Point2 ofs=offset;
 			if (centered)
 				ofs-=s/2;
 
-			Rect2i dst_rect(ofs,s);
+			Rect2 dst_rect(ofs,s);
 
 			if (hflip)
 				dst_rect.size.x=-dst_rect.size.x;
@@ -284,7 +284,7 @@ Rect2 AnimatedSprite::get_item_rect() const {
 		return Node2D::get_item_rect();
 	Size2i s = t->get_size();
 
-	Point2i ofs=offset;
+	Point2 ofs=offset;
 	if (centered)
 		ofs-=s/2;
 

+ 5 - 5
scene/2d/sprite.cpp

@@ -82,7 +82,7 @@ void Sprite::_notification(int p_what) {
 
 			}
 
-			Point2i ofs=offset;
+			Point2 ofs=offset;
 			if (centered)
 				ofs-=s/2;
 
@@ -265,7 +265,7 @@ Rect2 Sprite::get_item_rect() const {
 		s=s/Point2(hframes,vframes);
 	}
 
-	Point2i ofs=offset;
+	Point2 ofs=offset;
 	if (centered)
 		ofs-=s/2;
 
@@ -413,11 +413,11 @@ void ViewportSprite::_notification(int p_what) {
 
 			src_rect.size=s;
 
-			Point2i ofs=offset;
+			Point2 ofs=offset;
 			if (centered)
 				ofs-=s/2;
 
-			Rect2i dst_rect(ofs,s);
+			Rect2 dst_rect(ofs,s);
 			texture->draw_rect_region(ci,dst_rect,src_rect,modulate);
 
 		} break;
@@ -505,7 +505,7 @@ Rect2 ViewportSprite::get_item_rect() const {
 	Size2i s;
 
 	s = texture->get_size();
-	Point2i ofs=offset;
+	Point2 ofs=offset;
 	if (centered)
 		ofs-=s/2;
 

+ 240 - 14
scene/3d/area.cpp

@@ -225,27 +225,56 @@ void Area::_clear_monitoring() {
 	}
 	ERR_FAIL_COND(locked);
 
-	Map<ObjectID,BodyState> bmcopy = body_map;
-	body_map.clear();
-	//disconnect all monitored stuff
+	{
+		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()) {
+		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_tree)
-			continue;
+			Object *obj = ObjectDB::get_instance(E->key());
+			Node *node = obj ? obj->cast_to<Node>() : NULL;
+			ERR_CONTINUE(!node);
+			if (!E->get().in_tree)
+				continue;
+
+			for(int i=0;i<E->get().shapes.size();i++) {
 
-		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_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_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
+			node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
 		}
 
-		emit_signal(SceneStringNames::get_singleton()->body_exit,obj);
+	}
+
+	{
+
+		Map<ObjectID,AreaState> bmcopy = area_map;
+		area_map.clear();
+		//disconnect all monitored stuff
+
+		for (Map<ObjectID,AreaState>::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_tree)
+				continue;
+
+			for(int i=0;i<E->get().shapes.size();i++) {
 
-		node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree);
-		node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree);
+				emit_signal(SceneStringNames::get_singleton()->area_exit_shape,E->key(),node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+			}
+
+			emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
+
+			node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+			node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+		}
 	}
 
 }
@@ -271,10 +300,127 @@ void Area::set_enable_monitoring(bool p_enable) {
 	if (monitoring) {
 
 		PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout");
+		PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout");
 	} else {
 		PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName());
+		PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName());
 		_clear_monitoring();
+
+	}
+}
+
+
+void Area::_area_enter_tree(ObjectID p_id) {
+
+	Object *obj = ObjectDB::get_instance(p_id);
+	Node *node = obj ? obj->cast_to<Node>() : NULL;
+	ERR_FAIL_COND(!node);
+
+	Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+	ERR_FAIL_COND(!E);
+	ERR_FAIL_COND(E->get().in_tree);
+
+	E->get().in_tree=true;
+	emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+	for(int i=0;i<E->get().shapes.size();i++) {
+
+		emit_signal(SceneStringNames::get_singleton()->area_enter_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
+	}
+
+}
+
+void Area::_area_exit_tree(ObjectID p_id) {
+
+	Object *obj = ObjectDB::get_instance(p_id);
+	Node *node = obj ? obj->cast_to<Node>() : NULL;
+	ERR_FAIL_COND(!node);
+	Map<ObjectID,AreaState>::Element *E=area_map.find(p_id);
+	ERR_FAIL_COND(!E);
+	ERR_FAIL_COND(!E->get().in_tree);
+	E->get().in_tree=false;
+	emit_signal(SceneStringNames::get_singleton()->area_exit,node);
+	for(int i=0;i<E->get().shapes.size();i++) {
+
+		emit_signal(SceneStringNames::get_singleton()->area_exit_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape);
 	}
+
+}
+
+void Area::_area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape) {
+
+
+	bool area_in = p_status==PhysicsServer::AREA_BODY_ADDED;
+	ObjectID objid=p_instance;
+
+	Object *obj = ObjectDB::get_instance(objid);
+	Node *node = obj ? obj->cast_to<Node>() : NULL;
+
+	Map<ObjectID,AreaState>::Element *E=area_map.find(objid);
+
+	ERR_FAIL_COND(!area_in && !E);
+
+	locked=true;
+
+	if (area_in) {
+		if (!E) {
+
+			E = area_map.insert(objid,AreaState());
+			E->get().rc=0;
+			E->get().in_tree=node && node->is_inside_tree();
+			if (node) {
+				node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree,make_binds(objid));
+				node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree,make_binds(objid));
+				if (E->get().in_tree) {
+					emit_signal(SceneStringNames::get_singleton()->area_enter,node);
+
+				}
+			}
+
+		}
+		E->get().rc++;
+		if (node)
+			E->get().shapes.insert(AreaShapePair(p_area_shape,p_self_shape));
+
+
+		if (!node || E->get().in_tree) {
+			emit_signal(SceneStringNames::get_singleton()->area_enter_shape,objid,node,p_area_shape,p_self_shape);
+		}
+
+	} else {
+
+		E->get().rc--;
+
+		if (node)
+			E->get().shapes.erase(AreaShapePair(p_area_shape,p_self_shape));
+
+		bool eraseit=false;
+
+		if (E->get().rc==0) {
+
+			if (node) {
+				node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree);
+				node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree);
+				if (E->get().in_tree) {
+					emit_signal(SceneStringNames::get_singleton()->area_exit,obj);
+				}
+
+			}
+
+			eraseit=true;
+
+		}
+		if (!node || E->get().in_tree) {
+			emit_signal(SceneStringNames::get_singleton()->area_exit_shape,objid,obj,p_area_shape,p_self_shape);
+		}
+
+		if (eraseit)
+			area_map.erase(E);
+
+	}
+
+	locked=false;
+
+
 }
 
 bool Area::is_monitoring_enabled() const {
@@ -302,11 +448,76 @@ Array Area::get_overlapping_bodies() const {
 	return ret;
 }
 
+void Area::set_monitorable(bool p_enable) {
+
+	if (locked) {
+		ERR_EXPLAIN("This function can't be used during the in/out signal.");
+	}
+	ERR_FAIL_COND(locked);
+
+	if (p_enable==monitorable)
+		return;
+
+	monitorable=p_enable;
+
+	PhysicsServer::get_singleton()->area_set_monitorable(get_rid(),monitorable);
+}
+
+bool Area::is_monitorable() const {
+
+	return monitorable;
+}
+
+
+Array Area::get_overlapping_areas() const {
+
+	ERR_FAIL_COND_V(!monitoring,Array());
+	Array ret;
+	ret.resize(area_map.size());
+	int idx=0;
+	for (const Map<ObjectID,AreaState>::Element *E=area_map.front();E;E=E->next()) {
+		Object *obj = ObjectDB::get_instance(E->key());
+		if (!obj) {
+			ret.resize( ret.size() -1 ); //ops
+		} else {
+			ret[idx++]=obj;
+		}
+
+	}
+
+	return ret;
+}
+
+bool Area::overlaps_area(Node* p_area) const {
+
+	ERR_FAIL_NULL_V(p_area,false);
+	const Map<ObjectID,AreaState>::Element *E=area_map.find(p_area->get_instance_ID());
+	if (!E)
+		return false;
+	return E->get().in_tree;
+
+
+
+}
+
+bool Area::overlaps_body(Node* p_body) const{
+
+	ERR_FAIL_NULL_V(p_body,false);
+	const Map<ObjectID,BodyState>::Element *E=body_map.find(p_body->get_instance_ID());
+	if (!E)
+		return false;
+	return E->get().in_tree;
+
+}
+
 void Area::_bind_methods() {
 
 	ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area::_body_enter_tree);
 	ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area::_body_exit_tree);
 
+	ObjectTypeDB::bind_method(_MD("_area_enter_tree","id"),&Area::_area_enter_tree);
+	ObjectTypeDB::bind_method(_MD("_area_exit_tree","id"),&Area::_area_exit_tree);
+
 	ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area::set_space_override_mode);
 	ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area::get_space_override_mode);
 
@@ -328,13 +539,21 @@ void Area::_bind_methods() {
 	ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority);
 	ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority);
 
+	ObjectTypeDB::bind_method(_MD("set_monitorable","enable"),&Area::set_monitorable);
+	ObjectTypeDB::bind_method(_MD("is_monitorable"),&Area::is_monitorable);
+
 
 	ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area::set_enable_monitoring);
 	ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area::is_monitoring_enabled);
 
 	ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area::get_overlapping_bodies);
+	ObjectTypeDB::bind_method(_MD("get_overlapping_areas"),&Area::get_overlapping_areas);
+
+	ObjectTypeDB::bind_method(_MD("overlaps_body:PhysicsBody","body"),&Area::overlaps_body);
+	ObjectTypeDB::bind_method(_MD("overlaps_area:Area","area"),&Area::overlaps_area);
 
 	ObjectTypeDB::bind_method(_MD("_body_inout"),&Area::_body_inout);
+	ObjectTypeDB::bind_method(_MD("_area_inout"),&Area::_area_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")));
@@ -342,6 +561,11 @@ void Area::_bind_methods() {
 	ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body")));
 	ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body")));
 
+	ADD_SIGNAL( MethodInfo("area_enter_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+	ADD_SIGNAL( MethodInfo("area_exit_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape")));
+	ADD_SIGNAL( MethodInfo("area_enter",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area")));
+	ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area")));
+
 	ADD_PROPERTY( 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::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale"));
@@ -350,6 +574,7 @@ void Area::_bind_methods() {
 	ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density"));
 	ADD_PROPERTY( 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"));
+	ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable"));
 
 }
 
@@ -366,6 +591,7 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru
 	monitoring=false;
 	set_ray_pickable(false);
 	set_enable_monitoring(true);
+	set_monitorable(true);
 
 }
 

+ 38 - 0
scene/3d/area.h

@@ -53,6 +53,7 @@ private:
 	real_t density;
 	int priority;
 	bool monitoring;
+	bool monitorable;
 	bool locked;
 
 
@@ -84,6 +85,36 @@ private:
 	};
 
 	Map<ObjectID,BodyState> body_map;
+
+
+	void _area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape);
+
+	void _area_enter_tree(ObjectID p_id);
+	void _area_exit_tree(ObjectID p_id);
+
+	struct AreaShapePair {
+
+		int area_shape;
+		int self_shape;
+		bool operator<(const AreaShapePair& p_sp) const {
+			if (area_shape==p_sp.area_shape)
+				return self_shape < p_sp.self_shape;
+			else
+				return area_shape < p_sp.area_shape;
+		}
+
+		AreaShapePair() {}
+		AreaShapePair(int p_bs, int p_as) { area_shape=p_bs; self_shape=p_as; }
+	};
+
+	struct AreaState {
+
+		int rc;
+		bool in_tree;
+		VSet<AreaShapePair> shapes;
+	};
+
+	Map<ObjectID,AreaState> area_map;
 	void _clear_monitoring();
 
 
@@ -117,7 +148,14 @@ public:
 	void set_enable_monitoring(bool p_enable);
 	bool is_monitoring_enabled() const;
 
+	void set_monitorable(bool p_enable);
+	bool is_monitorable() const;
+
 	Array get_overlapping_bodies() const;
+	Array get_overlapping_areas() const; //function for script
+
+	bool overlaps_area(Node* p_area) const;
+	bool overlaps_body(Node* p_body) const;
 
 
 	Area();

+ 4 - 2
scene/main/scene_main_loop.cpp

@@ -1108,6 +1108,9 @@ void SceneTree::_bind_methods() {
 	ADD_SIGNAL( MethodInfo("node_removed",PropertyInfo( Variant::OBJECT, "node") ) );
 	ADD_SIGNAL( MethodInfo("screen_resized") );
 
+	ADD_SIGNAL( MethodInfo("idle_frame"));
+	ADD_SIGNAL( MethodInfo("fixed_frame"));
+
 	BIND_CONSTANT( GROUP_CALL_DEFAULT );
 	BIND_CONSTANT( GROUP_CALL_REVERSE );
 	BIND_CONSTANT( GROUP_CALL_REALTIME );
@@ -1166,8 +1169,7 @@ SceneTree::SceneTree() {
 	edited_scene_root=NULL;
 #endif
 
-	ADD_SIGNAL( MethodInfo("idle_frame"));
-	ADD_SIGNAL( MethodInfo("fixed_frame"));
+
 
 }
 

+ 69 - 0
servers/physics/area_pair_sw.cpp

@@ -93,3 +93,72 @@ AreaPairSW::~AreaPairSW() {
 	body->remove_constraint(this);
 	area->remove_constraint(this);
 }
+
+////////////////////////////////////////////////////
+
+
+
+bool Area2PairSW::setup(float p_step) {
+
+//	bool result = area_a->test_collision_mask(area_b) && CollisionSolverSW::solve(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),Vector2(),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),Vector2(),NULL,this);
+	bool result = CollisionSolverSW::solve_static(area_a->get_shape(shape_a),area_a->get_transform() * area_a->get_shape_transform(shape_a),area_b->get_shape(shape_b),area_b->get_transform() * area_b->get_shape_transform(shape_b),NULL,this);
+
+	if (result!=colliding) {
+
+		if (result) {
+
+			if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+				area_b->add_area_to_query(area_a,shape_a,shape_b);
+
+			if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+				area_a->add_area_to_query(area_b,shape_b,shape_a);
+
+		} else {
+
+			if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+				area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+			if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+				area_a->remove_area_from_query(area_b,shape_b,shape_a);
+		}
+
+		colliding=result;
+
+	}
+
+	return false; //never do any post solving
+}
+
+void Area2PairSW::solve(float p_step) {
+
+
+}
+
+
+Area2PairSW::Area2PairSW(AreaSW *p_area_a,int p_shape_a, AreaSW *p_area_b,int p_shape_b) {
+
+
+	area_a=p_area_a;
+	area_b=p_area_b;
+	shape_a=p_shape_a;
+	shape_b=p_shape_b;
+	colliding=false;
+	area_a->add_constraint(this);
+	area_b->add_constraint(this);
+
+}
+
+Area2PairSW::~Area2PairSW() {
+
+	if (colliding) {
+
+		if (area_b->has_area_monitor_callback() && area_a->is_monitorable())
+			area_b->remove_area_from_query(area_a,shape_a,shape_b);
+
+		if (area_a->has_area_monitor_callback() && area_b->is_monitorable())
+			area_a->remove_area_from_query(area_b,shape_b,shape_a);
+	}
+
+	area_a->remove_constraint(this);
+	area_b->remove_constraint(this);
+}

+ 18 - 0
servers/physics/area_pair_sw.h

@@ -49,5 +49,23 @@ public:
 	~AreaPairSW();
 };
 
+
+class Area2PairSW : public ConstraintSW {
+
+	AreaSW *area_a;
+	AreaSW *area_b;
+	int shape_a;
+	int shape_b;
+	bool colliding;
+public:
+
+	bool setup(float p_step);
+	void solve(float p_step);
+
+	Area2PairSW(AreaSW *p_area_a,int p_shape_a, AreaSW *p_area_b,int p_shape_b);
+	~Area2PairSW();
+};
+
+
 #endif // AREA_PAIR__SW_H
 

+ 69 - 0
servers/physics/area_sw.cpp

@@ -31,6 +31,7 @@
 #include "body_sw.h"
 
 AreaSW::BodyKey::BodyKey(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
+AreaSW::BodyKey::BodyKey(AreaSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape) { rid=p_body->get_self(); instance_id=p_body->get_instance_id(); body_shape=p_body_shape; area_shape=p_area_shape; }
 
 void AreaSW::_shapes_changed() {
 
@@ -57,6 +58,7 @@ void AreaSW::set_space(SpaceSW *p_space) {
 	}
 
 	monitored_bodies.clear();
+	monitored_areas.clear();
 
 	_set_space(p_space);
 }
@@ -76,11 +78,32 @@ void AreaSW::set_monitor_callback(ObjectID p_id, const StringName& p_method) {
 	monitor_callback_method=p_method;
 
 	monitored_bodies.clear();
+	monitored_areas.clear();
+
 
 	_shape_changed();
 
 }
 
+void AreaSW::set_area_monitor_callback(ObjectID p_id, const StringName& p_method) {
+
+
+	if (p_id==area_monitor_callback_id) {
+		area_monitor_callback_method=p_method;
+		return;
+	}
+
+	_unregister_shapes();
+
+	area_monitor_callback_id=p_id;
+	area_monitor_callback_method=p_method;
+
+	monitored_bodies.clear();
+	monitored_areas.clear();
+
+	_shape_changed();
+
+}
 
 
 void AreaSW::set_space_override_mode(PhysicsServer::AreaSpaceOverrideMode p_mode) {
@@ -134,6 +157,15 @@ void AreaSW::_queue_monitor_update() {
 
 }
 
+void AreaSW::set_monitorable(bool p_monitorable) {
+
+	if (monitorable==p_monitorable)
+		return;
+
+	monitorable=p_monitorable;
+	_set_static(!monitorable);
+}
+
 void AreaSW::call_queries() {
 
 	if (monitor_callback_id && !monitored_bodies.empty()) {
@@ -168,6 +200,41 @@ void AreaSW::call_queries() {
 
 	monitored_bodies.clear();
 
+	if (area_monitor_callback_id && !monitored_areas.empty()) {
+
+
+		Variant res[5];
+		Variant *resptr[5];
+		for(int i=0;i<5;i++)
+			resptr[i]=&res[i];
+
+		Object *obj = ObjectDB::get_instance(area_monitor_callback_id);
+		if (!obj) {
+			monitored_areas.clear();
+			area_monitor_callback_id=0;
+			return;
+		}
+
+
+
+		for (Map<BodyKey,BodyState>::Element *E=monitored_areas.front();E;E=E->next()) {
+
+			if (E->get().state==0)
+				continue; //nothing happened
+
+			res[0]=E->get().state>0 ? PhysicsServer::AREA_BODY_ADDED : PhysicsServer::AREA_BODY_REMOVED;
+			res[1]=E->key().rid;
+			res[2]=E->key().instance_id;
+			res[3]=E->key().body_shape;
+			res[4]=E->key().area_shape;
+
+
+			Variant::CallError ce;
+			obj->call(area_monitor_callback_method,(const Variant**)resptr,5,ce);
+		}
+	}
+
+	monitored_areas.clear();
 	//get_space()->area_remove_from_monitor_query_list(&monitor_query_list);
 
 }
@@ -185,6 +252,8 @@ AreaSW::AreaSW() : CollisionObjectSW(TYPE_AREA), monitor_query_list(this),  move
 	priority=0;
 	set_ray_pickable(false);
 	monitor_callback_id=0;
+	area_monitor_callback_id=0;
+	monitorable=false;
 
 }
 

+ 35 - 2
servers/physics/area_sw.h

@@ -49,10 +49,14 @@ class AreaSW : public CollisionObjectSW{
 	float point_attenuation;
 	float density;
 	int priority;
+	bool monitorable;
 
 	ObjectID monitor_callback_id;
 	StringName monitor_callback_method;
 
+	ObjectID area_monitor_callback_id;
+	StringName area_monitor_callback_method;
+
 	SelfList<AreaSW> monitor_query_list;
 	SelfList<AreaSW> moved_list;
 
@@ -79,6 +83,8 @@ class AreaSW : public CollisionObjectSW{
 
 		_FORCE_INLINE_ BodyKey() {}
 		BodyKey(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+		BodyKey(AreaSW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
+
 	};
 
 	struct BodyState {
@@ -90,6 +96,7 @@ class AreaSW : public CollisionObjectSW{
 	};
 
 	Map<BodyKey,BodyState> monitored_bodies;
+	Map<BodyKey,BodyState> monitored_areas;
 
 	//virtual void shape_changed_notify(ShapeSW *p_shape);
 	//virtual void shape_deleted_notify(ShapeSW *p_shape);
@@ -108,9 +115,15 @@ public:
 	void set_monitor_callback(ObjectID p_id, const StringName& p_method);
 	_FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id; }
 
+	void set_area_monitor_callback(ObjectID p_id, const StringName& p_method);
+	_FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id; }
+
 	_FORCE_INLINE_ void add_body_to_query(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
 	_FORCE_INLINE_ void remove_body_from_query(BodySW *p_body, uint32_t p_body_shape,uint32_t p_area_shape);
 
+	_FORCE_INLINE_ void add_area_to_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+	_FORCE_INLINE_ void remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape);
+
 	void set_param(PhysicsServer::AreaParameter p_param, const Variant& p_value);
 	Variant get_param(PhysicsServer::AreaParameter p_param) const;
 
@@ -142,8 +155,8 @@ public:
 	_FORCE_INLINE_ void remove_constraint( ConstraintSW* p_constraint) { constraints.erase(p_constraint); }
 	_FORCE_INLINE_ const Set<ConstraintSW*>& get_constraints() const { return constraints; }
 
-
-
+	void set_monitorable(bool p_monitorable);
+	_FORCE_INLINE_ bool is_monitorable() const { return monitorable; }
 
 	void set_transform(const Transform& p_transform);
 
@@ -172,6 +185,26 @@ void AreaSW::remove_body_from_query(BodySW *p_body, uint32_t p_body_shape,uint32
 }
 
 
+void AreaSW::add_area_to_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+	BodyKey bk(p_area,p_area_shape,p_self_shape);
+	monitored_areas[bk].inc();
+	if (!monitor_query_list.in_list())
+		_queue_monitor_update();
+
+
+}
+void AreaSW::remove_area_from_query(AreaSW *p_area, uint32_t p_area_shape,uint32_t p_self_shape) {
+
+
+	BodyKey bk(p_area,p_area_shape,p_self_shape);
+	monitored_areas[bk].dec();
+	if (!monitor_query_list.in_list())
+		_queue_monitor_update();
+}
+
+
 
 
 

+ 16 - 0
servers/physics/physics_server_sw.cpp

@@ -394,6 +394,14 @@ Transform PhysicsServerSW::area_get_transform(RID p_area) const {
 	return area->get_transform();
 };
 
+void PhysicsServerSW::area_set_monitorable(RID p_area,bool p_monitorable) {
+
+	AreaSW *area = area_owner.get(p_area);
+	ERR_FAIL_COND(!area);
+
+	area->set_monitorable(p_monitorable);
+}
+
 void PhysicsServerSW::area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
 
 	AreaSW *area = area_owner.get(p_area);
@@ -423,6 +431,14 @@ bool PhysicsServerSW::area_is_ray_pickable(RID p_area) const{
 }
 
 
+void PhysicsServerSW::area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method) {
+
+
+	AreaSW *area = area_owner.get(p_area);
+	ERR_FAIL_COND(!area);
+
+	area->set_area_monitor_callback(p_receiver?p_receiver->get_instance_ID():0,p_method);
+}
 
 /* BODY API */
 

+ 3 - 0
servers/physics/physics_server_sw.h

@@ -128,7 +128,10 @@ public:
 	virtual void area_set_ray_pickable(RID p_area,bool p_enable);
 	virtual bool area_is_ray_pickable(RID p_area) const;
 
+	virtual void area_set_monitorable(RID p_area,bool p_monitorable);
+
 	virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method);
+	virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method);
 
 
 	/* BODY API */

+ 9 - 6
servers/physics/space_sw.cpp

@@ -503,15 +503,18 @@ void* SpaceSW::_broadphase_pair(CollisionObjectSW *A,int p_subindex_A,CollisionO
 
 	if (type_A==CollisionObjectSW::TYPE_AREA) {
 
-
-		ERR_FAIL_COND_V(type_B!=CollisionObjectSW::TYPE_BODY,NULL);
 		AreaSW *area=static_cast<AreaSW*>(A);
-		BodySW *body=static_cast<BodySW*>(B);
-
+		if (type_B==CollisionObjectSW::TYPE_AREA) {
 
-		AreaPairSW *area_pair = memnew(AreaPairSW(body,p_subindex_B,area,p_subindex_A) );
+			AreaSW *area_b=static_cast<AreaSW*>(B);
+			Area2PairSW *area2_pair = memnew(Area2PairSW(area_b,p_subindex_B,area,p_subindex_A) );
+			return area2_pair;
+		} else {
 
-		return area_pair;
+			BodySW *body=static_cast<BodySW*>(B);
+			AreaPairSW *area_pair = memnew(AreaPairSW(body,p_subindex_B,area,p_subindex_A) );
+			return area_pair;
+		}
 	} else {
 
 

+ 3 - 0
servers/physics_server.h

@@ -339,7 +339,10 @@ public:
 	virtual Variant area_get_param(RID p_parea,AreaParameter p_param) const=0;
 	virtual Transform area_get_transform(RID p_area) const=0;
 
+	virtual void area_set_monitorable(RID p_area,bool p_monitorable)=0;
+
 	virtual void area_set_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0;
+	virtual void area_set_area_monitor_callback(RID p_area,Object *p_receiver,const StringName& p_method)=0;
 
 	virtual void area_set_ray_pickable(RID p_area,bool p_enable)=0;
 	virtual bool area_is_ray_pickable(RID p_area) const=0;

+ 42 - 4
tools/editor/plugins/canvas_item_editor_plugin.cpp

@@ -150,8 +150,46 @@ void CanvasItemEditor::_unhandled_key_input(const InputEvent& p_ev) {
 		_tool_select(TOOL_MOVE);
 	if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_E)
 		_tool_select(TOOL_ROTATE);
-	if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_V && drag==DRAG_ALL && can_move_pivot)
-		drag=DRAG_PIVOT;
+	if (p_ev.key.pressed && !p_ev.key.echo && p_ev.key.scancode==KEY_V && drag==DRAG_NONE && can_move_pivot) {
+		if (p_ev.key.mod.shift) {
+			//move drag pivot
+			drag=DRAG_PIVOT;
+		} else if (!Input::get_singleton()->is_mouse_button_pressed(0)) {
+
+			List<Node*> &selection = editor_selection->get_selected_node_list();
+
+			Vector2 mouse_pos = viewport->get_local_mouse_pos();
+			if (selection.size() && viewport->get_rect().has_point(mouse_pos)) {
+				//just in case, make it work if over viewport
+				mouse_pos=transform.affine_inverse().xform(mouse_pos);
+				mouse_pos=snap_point(mouse_pos);
+
+				undo_redo->create_action("Move Pivot");
+
+				for(List<Node*>::Element *E=selection.front();E;E=E->next()) {
+
+					Node2D *n2d = E->get()->cast_to<Node2D>();
+
+					if (n2d && n2d->edit_has_pivot()) {
+
+						Vector2 offset = n2d->edit_get_pivot();
+						Vector2 gpos = n2d->get_global_pos();
+
+
+						undo_redo->add_do_method(n2d,"set_global_pos",mouse_pos);
+						undo_redo->add_do_method(n2d,"edit_set_pivot",offset+(gpos-mouse_pos));
+						undo_redo->add_undo_method(n2d,"set_global_pos",gpos);
+						undo_redo->add_undo_method(n2d,"edit_set_pivot",offset);
+
+					}
+
+				}
+
+				undo_redo->commit_action();
+			}
+
+		}
+	}
 
 }
 
@@ -1685,7 +1723,7 @@ void CanvasItemEditor::_viewport_draw() {
 			viewport->draw_line(endpoints[i],endpoints[(i+1)%4],c,2);
 		}
 
-		if (single && (tool==TOOL_SELECT || tool == TOOL_MOVE)) { //kind of sucks
+		if (single && (tool==TOOL_SELECT || tool == TOOL_MOVE || tool == TOOL_ROTATE)) { //kind of sucks
 
 			if (canvas_item->cast_to<Node2D>()) {
 
@@ -2854,7 +2892,7 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) {
 	hb->add_child(select_button);
 	select_button->connect("pressed",this,"_tool_select",make_binds(TOOL_SELECT));
 	select_button->set_pressed(true);
-	select_button->set_tooltip("Select Mode (Q)\n"+keycode_get_string(KEY_MASK_CMD)+"Drag: Rotate\nAlt+Drag: Move\nPress 'v' to Move Pivot (while moving)");
+	select_button->set_tooltip("Select Mode (Q)\n"+keycode_get_string(KEY_MASK_CMD)+"Drag: Rotate\nAlt+Drag: Move\nPress 'v' to Change Pivot, 'Shift+v' to Drag Pivot (while moving).");
 
 	move_button = memnew( ToolButton );
 	move_button->set_toggle_mode(true);