Пример #1
0
bool Space2DSW::test_body_motion(Body2DSW *p_body, const Matrix32 &p_from, const Vector2&p_motion, float p_margin, Physics2DServer::MotionResult *r_result) {

	//give me back regular physics engine logic
	//this is madness
	//and most people using this function will think
	//what it does is simpler than using physics
	//this took about a week to get right..
	//but is it right? who knows at this point..

	if (r_result) {
		r_result->collider_id=0;
		r_result->collider_shape=0;

	}
	Rect2 body_aabb;

	for(int i=0;i<p_body->get_shape_count();i++) {

		if (i==0)
			body_aabb=p_body->get_shape_aabb(i);
		else
			body_aabb=body_aabb.merge(p_body->get_shape_aabb(i));
	}

	body_aabb=body_aabb.grow(p_margin);

	Matrix32 body_transform = p_from;

	{
		//STEP 1, FREE BODY IF STUCK

		const int max_results = 32;
		int recover_attempts=4;
		Vector2 sr[max_results*2];

		do {

			Physics2DServerSW::CollCbkData cbk;
			cbk.max=max_results;
			cbk.amount=0;
			cbk.ptr=sr;


			CollisionSolver2DSW::CallbackResult cbkres=NULL;

			Physics2DServerSW::CollCbkData *cbkptr=NULL;
			cbkptr=&cbk;
			cbkres=Physics2DServerSW::_shape_col_cbk;

			bool collided=false;

			int amount = _cull_aabb_for_body(p_body,body_aabb);

			for(int j=0;j<p_body->get_shape_count();j++) {
				if (p_body->is_shape_set_as_trigger(j))
					continue;

				Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j);
				Shape2DSW *body_shape = p_body->get_shape(j);
				for(int i=0;i<amount;i++) {

					const CollisionObject2DSW *col_obj=intersection_query_results[i];
					int shape_idx=intersection_query_subindex_results[i];

					if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {

						const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);

						Vector2 cdir = body->get_one_way_collision_direction();
						//if (cdir!=Vector2() && p_motion.dot(cdir)<0)
						//	continue;

						cbk.valid_dir=cdir;
						cbk.valid_depth=body->get_one_way_collision_max_depth();
					} else {
						cbk.valid_dir=Vector2();
						cbk.valid_depth=0;
					}

					if (CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2(),cbkres,cbkptr,NULL,p_margin)) {
						collided=cbk.amount>0;
					}
				}
			}


			if (!collided)
				break;

			Vector2 recover_motion;

			for(int i=0;i<cbk.amount;i++) {

				Vector2 a = sr[i*2+0];
				Vector2 b = sr[i*2+1];

#if 0
				Vector2 rel = b-a;
				float d = rel.length();
				if (d==0)
					continue;

				Vector2 n = rel/d;
				float traveled = n.dot(recover_motion);
				a+=n*traveled;

#endif
			//	float d = a.distance_to(b);

				//if (d<margin)
				///	continue;
				recover_motion+=(b-a)*0.4;
			}

			if (recover_motion==Vector2()) {
				collided=false;
				break;
			}

			body_transform.elements[2]+=recover_motion;
			body_aabb.pos+=recover_motion;

			recover_attempts--;

		} while (recover_attempts);
	}



	float safe = 1.0;
	float unsafe = 1.0;
	int best_shape=-1;

	{
		// STEP 2 ATTEMPT MOTION

		Rect2 motion_aabb=body_aabb;
		motion_aabb.pos+=p_motion;
		motion_aabb=motion_aabb.merge(body_aabb);

		int amount = _cull_aabb_for_body(p_body,motion_aabb);

		for(int j=0;j<p_body->get_shape_count();j++) {

			if (p_body->is_shape_set_as_trigger(j))
				continue;

			Matrix32 body_shape_xform = body_transform * p_body->get_shape_transform(j);
			Shape2DSW *body_shape = p_body->get_shape(j);

			bool stuck=false;

			float best_safe=1;
			float best_unsafe=1;

			for(int i=0;i<amount;i++) {

				const CollisionObject2DSW *col_obj=intersection_query_results[i];
				int shape_idx=intersection_query_subindex_results[i];


				Matrix32 col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx);
				//test initial overlap, does it collide if going all the way?
				if (!CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion,col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) {
					continue;
				}


				//test initial overlap
				if (CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj_xform,Vector2() ,NULL,NULL,NULL,0)) {

					if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {
						//if one way collision direction ignore initial overlap
						const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
						if (body->get_one_way_collision_direction()!=Vector2()) {
							continue;
						}
					}

					stuck=true;
					break;
				}


				//just do kinematic solving
				float low=0;
				float hi=1;
				Vector2 mnormal=p_motion.normalized();

				for(int i=0;i<8;i++) { //steps should be customizable..

					float ofs = (low+hi)*0.5;

					Vector2 sep=mnormal; //important optimization for this to work fast enough
					bool collided = CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion*ofs,col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),NULL,NULL,&sep,0);

					if (collided) {

						hi=ofs;
					} else {

						low=ofs;
					}
				}

				if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {

					const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
					if (body->get_one_way_collision_direction()!=Vector2()) {

						Vector2 cd[2];
						Physics2DServerSW::CollCbkData cbk;
						cbk.max=1;
						cbk.amount=0;
						cbk.ptr=cd;
						cbk.valid_dir=body->get_one_way_collision_direction();
						cbk.valid_depth=body->get_one_way_collision_max_depth();

						Vector2 sep=mnormal; //important optimization for this to work fast enough
						bool collided = CollisionSolver2DSW::solve(body_shape,body_shape_xform,p_motion*(hi+contact_max_allowed_penetration),col_obj->get_shape(shape_idx),col_obj_xform,Vector2(),Physics2DServerSW::_shape_col_cbk,&cbk,&sep,0);
						if (!collided || cbk.amount==0) {
							continue;
						}

					}
				}


				if (low<best_safe) {
					best_safe=low;
					best_unsafe=hi;
				}
			}

			if (stuck) {

				safe=0;
				unsafe=0;
				best_shape=j; //sadly it's the best
				break;
			}
			if (best_safe==1.0) {
				continue;
			}
			if (best_safe < safe) {

				safe=best_safe;
				unsafe=best_unsafe;
				best_shape=j;
			}
		}
	}

	bool collided=false;
	if (safe>=1) {
		//not collided
		collided=false;
		if (r_result) {

			r_result->motion=p_motion;
			r_result->remainder=Vector2();			
			r_result->motion+=(body_transform.elements[2]-p_from.elements[2]);
		}

	} else {

		//it collided, let's get the rest info in unsafe advance
		Matrix32 ugt = body_transform;
		ugt.elements[2]+=p_motion*unsafe;

		_RestCallbackData2D rcd;
		rcd.best_len=0;
		rcd.best_object=NULL;
		rcd.best_shape=0;

		Matrix32 body_shape_xform = ugt * p_body->get_shape_transform(best_shape);
		Shape2DSW *body_shape = p_body->get_shape(best_shape);

		body_aabb.pos+=p_motion*unsafe;

		int amount = _cull_aabb_for_body(p_body,body_aabb);


		for(int i=0;i<amount;i++) {


			const CollisionObject2DSW *col_obj=intersection_query_results[i];
			int shape_idx=intersection_query_subindex_results[i];

			if (col_obj->get_type()==CollisionObject2DSW::TYPE_BODY) {

				const Body2DSW *body=static_cast<const Body2DSW*>(col_obj);
				rcd.valid_dir=body->get_one_way_collision_direction();
				rcd.valid_depth=body->get_one_way_collision_max_depth();
			} else {
				rcd.valid_dir=Vector2();
				rcd.valid_depth=0;
			}


			rcd.object=col_obj;
			rcd.shape=shape_idx;
			bool sc = CollisionSolver2DSW::solve(body_shape,body_shape_xform,Vector2(),col_obj->get_shape(shape_idx),col_obj->get_transform() * col_obj->get_shape_transform(shape_idx),Vector2() ,_rest_cbk_result,&rcd,NULL,p_margin);
			if (!sc)
				continue;

		}

		if (rcd.best_len!=0) {

			if (r_result) {
				r_result->collider=rcd.best_object->get_self();
				r_result->collider_id=rcd.best_object->get_instance_id();
				r_result->collider_shape=rcd.best_shape;
				r_result->collision_normal=rcd.best_normal;
				r_result->collision_point=rcd.best_contact;
				r_result->collider_metadata=rcd.best_object->get_shape_metadata(rcd.best_shape);

				const Body2DSW *body = static_cast<const Body2DSW*>(rcd.best_object);
				Vector2 rel_vec = r_result->collision_point-body->get_transform().get_origin();
				r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity();

				r_result->motion=safe*p_motion;
				r_result->remainder=p_motion - safe * p_motion;
				r_result->motion+=(body_transform.elements[2]-p_from.elements[2]);

			}

			collided=true;
		} else {
			if (r_result) {

				r_result->motion=p_motion;
				r_result->remainder=Vector2();
				r_result->motion+=(body_transform.elements[2]-p_from.elements[2]);
			}

			collided=false;

		}
	}

	return collided;


#if 0
	//give me back regular physics engine logic
	//this is madness
	//and most people using this function will think
	//what it does is simpler than using physics
	//this took about a week to get right..
	//but is it right? who knows at this point..


	colliding=false;
	ERR_FAIL_COND_V(!is_inside_tree(),Vector2());
	Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space());
	ERR_FAIL_COND_V(!dss,Vector2());
	const int max_shapes=32;
	Vector2 sr[max_shapes*2];
	int res_shapes;

	Set<RID> exclude;
	exclude.insert(get_rid());


	//recover first
	int recover_attempts=4;

	bool collided=false;
	uint32_t mask=0;
	if (collide_static)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY;
	if (collide_kinematic)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
	if (collide_rigid)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY;
	if (collide_character)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY;

//	print_line("motion: "+p_motion+" margin: "+rtos(margin));

	//print_line("margin: "+rtos(margin));
	do {

		//motion recover
		for(int i=0;i<get_shape_count();i++) {

			if (is_shape_set_as_trigger(i))
				continue;
			if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask))
				collided=true;

		}

		if (!collided)
			break;

		Vector2 recover_motion;

		for(int i=0;i<res_shapes;i++) {

			Vector2 a = sr[i*2+0];
			Vector2 b = sr[i*2+1];

			float d = a.distance_to(b);

			//if (d<margin)
			///	continue;
			recover_motion+=(b-a)*0.4;
		}

		if (recover_motion==Vector2()) {
			collided=false;
			break;
		}

		Matrix32 gt = get_global_transform();
		gt.elements[2]+=recover_motion;
		set_global_transform(gt);

		recover_attempts--;

	} while (recover_attempts);


	//move second
	float safe = 1.0;
	float unsafe = 1.0;
	int best_shape=-1;

	for(int i=0;i<get_shape_count();i++) {

		if (is_shape_set_as_trigger(i))
			continue;

		float lsafe,lunsafe;
		bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask);
		//print_line("shape: "+itos(i)+" travel:"+rtos(ltravel));
		if (!valid) {

			safe=0;
			unsafe=0;
			best_shape=i; //sadly it's the best
			break;
		}
		if (lsafe==1.0) {
			continue;
		}
		if (lsafe < safe) {

			safe=lsafe;
			unsafe=lunsafe;
			best_shape=i;
		}
	}


	//print_line("best shape: "+itos(best_shape)+" motion "+p_motion);

	if (safe>=1) {
		//not collided
		colliding=false;
	} else {

		//it collided, let's get the rest info in unsafe advance
		Matrix32 ugt = get_global_transform();
		ugt.elements[2]+=p_motion*unsafe;
		Physics2DDirectSpaceState::ShapeRestInfo rest_info;
		bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask);
		if (!c2) {
			//should not happen, but floating point precision is so weird..

			colliding=false;
		} else {


			//print_line("Travel: "+rtos(travel));
			colliding=true;
			collision=rest_info.point;
			normal=rest_info.normal;
			collider=rest_info.collider_id;
			collider_vel=rest_info.linear_velocity;
			collider_shape=rest_info.shape;
			collider_metadata=rest_info.metadata;
		}

	}

	Vector2 motion=p_motion*safe;
	Matrix32 gt = get_global_transform();
	gt.elements[2]+=motion;
	set_global_transform(gt);

	return p_motion-motion;

#endif
	return false;
}
Пример #2
0
void GridMap::_octant_exit_world(const OctantKey &p_key) {

	ERR_FAIL_COND(!octant_map.has(p_key));
	Octant &g = *octant_map[p_key];
	PhysicsServer::get_singleton()->body_set_state(g.static_body, PhysicsServer::BODY_STATE_TRANSFORM, get_global_transform());
	PhysicsServer::get_singleton()->body_set_space(g.static_body, RID());

	if (g.collision_debug_instance.is_valid()) {

		VS::get_singleton()->instance_set_scenario(g.collision_debug_instance, RID());
	}

	for (int i = 0; i < g.multimesh_instances.size(); i++) {
		VS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID());
	}

	if (navigation) {
		for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {

			if (F->get().id >= 0) {
				navigation->navmesh_remove(F->get().id);
				F->get().id = -1;
			}
		}
	}
}
Пример #3
0
void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plot_meshes, List<PlotLight> &plot_lights) {

	MeshInstance *mi = Object::cast_to<MeshInstance>(p_at_node);
	if (mi && mi->get_flag(GeometryInstance::FLAG_USE_BAKED_LIGHT) && mi->is_visible_in_tree()) {
		Ref<Mesh> mesh = mi->get_mesh();
		if (mesh.is_valid()) {

			bool all_have_uv2 = true;
			for (int i = 0; i < mesh->get_surface_count(); i++) {
				if (!(mesh->surface_get_format(i) & Mesh::ARRAY_FORMAT_TEX_UV2)) {
					all_have_uv2 = false;
					break;
				}
			}

			if (all_have_uv2 && mesh->get_lightmap_size_hint() != Size2()) {
				//READY TO BAKE! size hint could be computed if not found, actually..

				AABB aabb = mesh->get_aabb();

				Transform xf = get_global_transform().affine_inverse() * mi->get_global_transform();

				if (AABB(-extents, extents * 2).intersects(xf.xform(aabb))) {
					PlotMesh pm;
					pm.local_xform = xf;
					pm.mesh = mesh;
					pm.path = get_path_to(mi);
					pm.instance_idx = -1;
					for (int i = 0; i < mesh->get_surface_count(); i++) {
						pm.instance_materials.push_back(mi->get_surface_material(i));
					}
					pm.override_material = mi->get_material_override();
					plot_meshes.push_back(pm);
				}
			}
		}
	}

	Spatial *s = Object::cast_to<Spatial>(p_at_node);

	if (!mi && s) {
		Array meshes = p_at_node->call("get_bake_meshes");
		if (meshes.size() && (meshes.size() & 1) == 0) {
			Transform xf = get_global_transform().affine_inverse() * s->get_global_transform();
			for (int i = 0; i < meshes.size(); i += 2) {
				PlotMesh pm;
				Transform mesh_xf = meshes[i + 1];
				pm.local_xform = xf * mesh_xf;
				pm.mesh = meshes[i];
				pm.instance_idx = i / 2;
				if (!pm.mesh.is_valid())
					continue;
				pm.path = get_path_to(s);
				plot_meshes.push_back(pm);
			}
		}
	}

	Light *light = Object::cast_to<Light>(p_at_node);

	if (light && light->get_bake_mode() != Light::BAKE_DISABLED) {
		PlotLight pl;
		Transform xf = get_global_transform().affine_inverse() * light->get_global_transform();

		pl.local_xform = xf;
		pl.light = light;
		plot_lights.push_back(pl);
	}
	for (int i = 0; i < p_at_node->get_child_count(); i++) {

		Node *child = p_at_node->get_child(i);
		if (!child->get_owner())
			continue; //maybe a helper

		_find_meshes_and_lights(child, plot_meshes, plot_lights);
	}
}
Пример #4
0
float Node2D::get_angle_to(const Vector2 &p_pos) const {

	return (get_global_transform().affine_inverse().xform(p_pos)).angle();
}
Пример #5
0
Point2 Node2D::to_global(Point2 p_local) const {

	return get_global_transform().xform(p_local);
}
Пример #6
0
Vector3 Spatial::to_local(Vector3 p_global) const {

	return get_global_transform().affine_inverse().xform(p_global);
}
Пример #7
0
float Node2D::get_global_rotation() const {

	return get_global_transform().get_rotation();
}
Пример #8
0
AABB VisualInstance::get_transformed_aabb() const {

	return get_global_transform().xform( get_aabb() );
}
Пример #9
0
Ref<InputEvent> CanvasItem::make_input_local(const Ref<InputEvent> &p_event) const {

	ERR_FAIL_COND_V(!is_inside_tree(), p_event);

	return p_event->xformed_by((get_canvas_transform() * get_global_transform()).affine_inverse());
}
Пример #10
0
Vector2 CanvasItem::get_local_mouse_pos() const{

	return (get_viewport_transform() * get_global_transform()).affine_inverse().xform(Input::get_singleton()->get_mouse_pos());
}
Пример #11
0
InputEvent CanvasItem::make_input_local(const InputEvent& p_event) const {

	ERR_FAIL_COND_V(!is_inside_tree(),p_event);

	InputEvent ev = p_event;

	Matrix32 local_matrix = (get_canvas_transform() * get_global_transform()).affine_inverse();

	switch(ev.type) {

		case InputEvent::MOUSE_BUTTON: {

			Vector2 g = local_matrix.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y));
			Vector2 l = local_matrix.xform(Vector2(ev.mouse_button.x,ev.mouse_button.y));
			ev.mouse_button.x=l.x;
			ev.mouse_button.y=l.y;
			ev.mouse_button.global_x=g.x;
			ev.mouse_button.global_y=g.y;

		} break;
		case InputEvent::MOUSE_MOTION: {

			Vector2 g = local_matrix.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y));
			Vector2 l = local_matrix.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y));
			Vector2 r = local_matrix.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y));
			Vector2 s = local_matrix.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y));
			ev.mouse_motion.x=l.x;
			ev.mouse_motion.y=l.y;
			ev.mouse_motion.global_x=g.x;
			ev.mouse_motion.global_y=g.y;
			ev.mouse_motion.relative_x=r.x;
			ev.mouse_motion.relative_y=r.y;
			ev.mouse_motion.speed_x=s.x;
			ev.mouse_motion.speed_y=s.y;

		} break;
		case InputEvent::SCREEN_TOUCH: {


			Vector2 t = local_matrix.xform(Vector2(ev.screen_touch.x,ev.screen_touch.y));
			ev.screen_touch.x=t.x;
			ev.screen_touch.y=t.y;

		} break;
		case InputEvent::SCREEN_DRAG: {


			Vector2 t = local_matrix.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y));
			Vector2 r = local_matrix.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y));
			Vector2 s = local_matrix.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y));
			ev.screen_drag.x=t.x;
			ev.screen_drag.y=t.y;
			ev.screen_drag.relative_x=r.x;
			ev.screen_drag.relative_y=r.y;
			ev.screen_drag.speed_x=s.x;
			ev.screen_drag.speed_y=s.y;
		} break;
	}

	return ev;
}
Пример #12
0
void RayCast2D::_notification(int p_what) {

	switch(p_what) {

		case NOTIFICATION_ENTER_TREE: {

			if (enabled && !get_tree()->is_editor_hint())
				set_fixed_process(true);
			else
				set_fixed_process(false);

		} break;
		case NOTIFICATION_EXIT_TREE: {

			if (enabled)
				set_fixed_process(false);

		} break;
#ifdef TOOLS_ENABLED
		case NOTIFICATION_DRAW: {

			if (!get_tree()->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,exclude,layer_mask)) {

				collided=true;
				against=rr.collider_id;
				collision_point=rr.position;
				collision_normal=rr.normal;
				against_shape=rr.shape;
			} else {
				collided=false;
			}



		} break;
	}
}
Пример #13
0
Transform2D Camera2D::get_camera_transform() {

	if (!get_tree())
		return Transform2D();

	ERR_FAIL_COND_V(custom_viewport && !ObjectDB::get_instance(custom_viewport_id), Transform2D());

	Size2 screen_size = viewport->get_visible_rect().size;

	Point2 new_camera_pos = get_global_transform().get_origin();
	Point2 ret_camera_pos;

	if (!first) {

		if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {

			if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {
				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 && !Engine::get_singleton()->is_editor_hint()) {

				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;
				}
			}

		} else if (anchor_mode == ANCHOR_MODE_FIXED_TOP_LEFT) {

			camera_pos = new_camera_pos;
		}

		Point2 screen_offset = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());
		Rect2 screen_rect(-screen_offset + camera_pos, screen_size * zoom);

		if (offset != Vector2())
			screen_rect.position += offset;

		if (limit_smoothing_enabled) {
			if (screen_rect.position.x < limit[MARGIN_LEFT])
				camera_pos.x -= screen_rect.position.x - limit[MARGIN_LEFT];

			if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT])
				camera_pos.x -= screen_rect.position.x + screen_rect.size.x - limit[MARGIN_RIGHT];

			if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
				camera_pos.y -= screen_rect.position.y + screen_rect.size.y - limit[MARGIN_BOTTOM];

			if (screen_rect.position.y < limit[MARGIN_TOP])
				camera_pos.y -= screen_rect.position.y - limit[MARGIN_TOP];
		}

		if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {

			float c = smoothing * get_fixed_process_delta_time();
			smoothed_camera_pos = ((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 = (anchor_mode == ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2());

	float angle = get_global_transform().get_rotation();
	if (rotating) {
		screen_offset = screen_offset.rotated(angle);
	}

	Rect2 screen_rect(-screen_offset + ret_camera_pos, screen_size * zoom);
	if (screen_rect.position.x < limit[MARGIN_LEFT])
		screen_rect.position.x = limit[MARGIN_LEFT];

	if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT])
		screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x;

	if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
		screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;

	if (screen_rect.position.y < limit[MARGIN_TOP])
		screen_rect.position.y = limit[MARGIN_TOP];

	if (offset != Vector2()) {

		screen_rect.position += offset;
		if (screen_rect.position.x + screen_rect.size.x > limit[MARGIN_RIGHT])
			screen_rect.position.x = limit[MARGIN_RIGHT] - screen_rect.size.x;

		if (screen_rect.position.y + screen_rect.size.y > limit[MARGIN_BOTTOM])
			screen_rect.position.y = limit[MARGIN_BOTTOM] - screen_rect.size.y;

		if (screen_rect.position.x < limit[MARGIN_LEFT])
			screen_rect.position.x = limit[MARGIN_LEFT];

		if (screen_rect.position.y < limit[MARGIN_TOP])
			screen_rect.position.y = limit[MARGIN_TOP];
	}

	camera_screen_center = screen_rect.position + screen_rect.size * 0.5;

	Transform2D xform;
	if (rotating) {
		xform.set_rotation(angle);
	}
	xform.scale_basis(zoom);
	xform.set_origin(screen_rect.position /*.floor()*/);

	/*
	if (0) {
		xform = get_global_transform() * xform;
	} else {
		xform.elements[2]+=get_global_transform().get_origin();
	}
*/

	return (xform).affine_inverse();
}
Пример #14
0
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_TREE: {

			if (custom_viewport && ObjectDB::get_instance(custom_viewport_id)) {
				viewport = custom_viewport;
			} else {
				viewport = get_viewport();
			}

			canvas = get_canvas();

			RID vp = viewport->get_viewport_rid();

			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);

			if (Engine::get_singleton()->is_editor_hint()) {
				set_fixed_process(false);
			}

			_update_scroll();
			first = true;

		} break;
		case NOTIFICATION_EXIT_TREE: {

			if (is_current()) {
				if (viewport && !(custom_viewport && !ObjectDB::get_instance(custom_viewport_id))) {
					viewport->set_canvas_transform(Transform2D());
				}
			}
			remove_from_group(group_name);
			remove_from_group(canvas_group_name);
			viewport = NULL;

		} break;
		case NOTIFICATION_DRAW: {

			if (!is_inside_tree() || !Engine::get_singleton()->is_editor_hint())
				break;

			if (screen_drawing_enabled) {
				Color area_axis_color(0.5, 0.42, 0.87, 0.63);
				float area_axis_width = 1;
				if (is_current()) {
					area_axis_width = 3;
					area_axis_color.a = 0.83;
				}

				Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
				Size2 screen_size = get_viewport_rect().size;

				Vector2 screen_endpoints[4] = {
					inv_camera_transform.xform(Vector2(0, 0)),
					inv_camera_transform.xform(Vector2(screen_size.width, 0)),
					inv_camera_transform.xform(Vector2(screen_size.width, screen_size.height)),
					inv_camera_transform.xform(Vector2(0, screen_size.height))
				};

				Transform2D inv_transform = get_global_transform().affine_inverse(); // undo global space

				for (int i = 0; i < 4; i++) {
					draw_line(inv_transform.xform(screen_endpoints[i]), inv_transform.xform(screen_endpoints[(i + 1) % 4]), area_axis_color, area_axis_width);
				}
			}

			if (limit_drawing_enabled) {
				Color limit_drawing_color(1, 1, 0, 0.63);
				float limit_drawing_width = 1;
				if (is_current()) {
					limit_drawing_color.a = 0.83;
					limit_drawing_width = 3;
				}

				Vector2 camera_origin = get_global_transform().get_origin();
				Vector2 camera_scale = get_global_transform().get_scale().abs();
				Vector2 limit_points[4] = {
					(Vector2(limit[MARGIN_LEFT], limit[MARGIN_TOP]) - camera_origin) / camera_scale,
					(Vector2(limit[MARGIN_RIGHT], limit[MARGIN_TOP]) - camera_origin) / camera_scale,
					(Vector2(limit[MARGIN_RIGHT], limit[MARGIN_BOTTOM]) - camera_origin) / camera_scale,
					(Vector2(limit[MARGIN_LEFT], limit[MARGIN_BOTTOM]) - camera_origin) / camera_scale
				};

				for (int i = 0; i < 4; i++) {
					draw_line(limit_points[i], limit_points[(i + 1) % 4], limit_drawing_color, limit_drawing_width);
				}
			}

			if (margin_drawing_enabled) {
				Color margin_drawing_color(0, 1, 1, 0.63);
				float margin_drawing_width = 1;
				if (is_current()) {
					margin_drawing_width = 3;
					margin_drawing_color.a = 0.83;
				}

				Transform2D inv_camera_transform = get_camera_transform().affine_inverse();
				Size2 screen_size = get_viewport_rect().size;

				Vector2 margin_endpoints[4] = {
					inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))),
					inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[MARGIN_RIGHT]), (screen_size.height / 2) - ((screen_size.height / 2) * drag_margin[MARGIN_TOP]))),
					inv_camera_transform.xform(Vector2((screen_size.width / 2) + ((screen_size.width / 2) * drag_margin[MARGIN_RIGHT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[MARGIN_BOTTOM]))),
					inv_camera_transform.xform(Vector2((screen_size.width / 2) - ((screen_size.width / 2) * drag_margin[MARGIN_LEFT]), (screen_size.height / 2) + ((screen_size.height / 2) * drag_margin[MARGIN_BOTTOM])))
				};

				Transform2D inv_transform = get_global_transform().affine_inverse(); // undo global space

				for (int i = 0; i < 4; i++) {
					draw_line(inv_transform.xform(margin_endpoints[i]), inv_transform.xform(margin_endpoints[(i + 1) % 4]), margin_drawing_color, margin_drawing_width);
				}
			}

		} break;
	}
}
Пример #15
0
void Spatial::global_scale(const Vector3 &p_scale) {

	Transform t = get_global_transform();
	t.basis.scale(p_scale);
	set_global_transform(t);
}
Пример #16
0
Vector2 CanvasItem::get_local_mouse_position() const {

	ERR_FAIL_COND_V(!get_viewport(), Vector2());

	return get_global_transform().affine_inverse().xform(get_global_mouse_position());
}
Пример #17
0
void Spatial::global_translate(const Vector3 &p_offset) {
	Transform t = get_global_transform();
	t.origin += p_offset;
	set_global_transform(t);
}
Пример #18
0
void LineEdit::_input_event(InputEvent p_event) {


    switch(p_event.type) {

    case InputEvent::MOUSE_BUTTON: {

        const InputEventMouseButton &b = p_event.mouse_button;

        if (b.pressed && b.button_index==BUTTON_RIGHT) {
            menu->set_pos(get_global_transform().xform(get_local_mouse_pos()));
            menu->set_size(Vector2(1,1));
            menu->popup();
            grab_focus();
            return;
        }

        if (b.button_index!=BUTTON_LEFT)
            break;

        _reset_caret_blink_timer();
        if (b.pressed) {

            shift_selection_check_pre(b.mod.shift);

            set_cursor_at_pixel_pos(b.x);

            if (b.mod.shift) {

                selection_fill_at_cursor();
                selection.creating=true;

            } else {

                if (b.doubleclick) {

                    selection.enabled=true;
                    selection.begin=0;
                    selection.end=text.length();
                    selection.doubleclick=true;
                }

                selection.drag_attempt=false;

                if ((cursor_pos<selection.begin) || (cursor_pos>selection.end) || !selection.enabled)  {

                    selection_clear();
                    selection.cursor_start=cursor_pos;
                    selection.creating=true;
                } else if (selection.enabled) {

                    selection.drag_attempt=true;
                }
            }

            //			if (!editable)
            //	non_editable_clicked_signal.call();
            update();

        } else {

            if ( (!selection.creating) && (!selection.doubleclick)) {
                selection_clear();
            }
            selection.creating=false;
            selection.doubleclick=false;

            if (OS::get_singleton()->has_virtual_keyboard())
                OS::get_singleton()->show_virtual_keyboard(text,get_global_rect());
        }

        update();
    }
    break;
    case InputEvent::MOUSE_MOTION: {

        const InputEventMouseMotion& m=p_event.mouse_motion;

        if (m.button_mask&BUTTON_LEFT) {

            if (selection.creating) {
                set_cursor_at_pixel_pos(m.x);
                selection_fill_at_cursor();
            }
        }

    }
    break;
    case InputEvent::KEY: {

        const InputEventKey &k =p_event.key;

        if (!k.pressed)
            return;
        unsigned int code  = k.scancode;


        if (k.mod.command) {

            bool handled=true;

            switch (code) {

            case (KEY_X): { // CUT

                if(editable) {
                    cut_text();
                }

            }
            break;

            case (KEY_C): { // COPY

                copy_text();

            }
            break;

            case (KEY_V): { // PASTE

                if(editable) {

                    paste_text();
                }

            }
            break;

            case (KEY_Z): { // Simple One level undo

                if(editable) {

                    undo();

                }


            }
            break;

            case (KEY_U): { // Delete from start to cursor

                if(editable) {

                    selection_clear();
                    undo_text = text;
                    text = text.substr(cursor_pos,text.length()-cursor_pos);

                    Ref<Font> font = get_font("font");

                    cached_width = 0;
                    if (font != NULL) {
                        for (int i = 0; i < text.length(); i++)
                            cached_width += font->get_char_size(text[i]).width;
                    }

                    set_cursor_pos(0);
                    _text_changed();

                }


            }
            break;

            case (KEY_Y): { // PASTE (Yank for unix users)

                if(editable) {

                    paste_text();
                }

            }
            break;
            case (KEY_K): { // Delete from cursor_pos to end

                if(editable) {

                    selection_clear();
                    undo_text = text;
                    text = text.substr(0,cursor_pos);
                    _text_changed();
                }

            }
            break;
            case (KEY_A): { //Select All
                select();
            }
            break;
            default: {
                handled=false;
            }
            }

            if (handled) {
                accept_event();
                return;
            }
        }

        _reset_caret_blink_timer();
        if (!k.mod.meta) {

            bool handled=true;
            switch (code) {

            case KEY_ENTER:
            case KEY_RETURN: {

                emit_signal( "text_entered",text );
                if (OS::get_singleton()->has_virtual_keyboard())
                    OS::get_singleton()->hide_virtual_keyboard();

                return;
            }
            break;

            case KEY_BACKSPACE: {

                if (!editable)
                    break;

                if (selection.enabled) {
                    undo_text=text;
                    selection_delete();
                    break;
                }

#ifdef APPLE_STYLE_KEYS
                if (k.mod.alt) {
#else
                if (k.mod.alt) {
                    handled=false;
                    break;
                } else if (k.mod.command) {
#endif
                    int cc=cursor_pos;
                    bool prev_char=false;

                    while (cc>0) {
                        bool ischar=_is_text_char(text[cc-1]);

                        if (prev_char && !ischar)
                            break;

                        prev_char=ischar;
                        cc--;
                    }

                    delete_text(cc, cursor_pos);

                    set_cursor_pos(cc);

                } else {
                    undo_text=text;
                    delete_char();
                }

            }
            break;
            case KEY_KP_4: {
                if (k.unicode != 0) {
                    handled = false;
                    break;
                }
                // numlock disabled. fallthrough to key_left
            }
            case KEY_LEFT: {

#ifndef APPLE_STYLE_KEYS
                if (!k.mod.alt)
#endif
                    shift_selection_check_pre(k.mod.shift);

#ifdef APPLE_STYLE_KEYS
                if (k.mod.command) {
                    set_cursor_pos(0);
                } else if (k.mod.alt) {

#else
                if (k.mod.alt) {
                    handled=false;
                    break;
                } else if (k.mod.command) {
#endif
                    bool prev_char=false;
                    int cc=cursor_pos;

                    while (cc>0) {
                        bool ischar=_is_text_char(text[cc-1]);

                        if (prev_char && !ischar)
                            break;

                        prev_char=ischar;
                        cc--;
                    }

                    set_cursor_pos(cc);

                } else {
                    set_cursor_pos(get_cursor_pos()-1);
                }

                shift_selection_check_post(k.mod.shift);

            }
            break;
            case KEY_KP_6: {
                if (k.unicode != 0) {
                    handled = false;
                    break;
                }
                // numlock disabled. fallthrough to key_right
            }
            case KEY_RIGHT: {

                shift_selection_check_pre(k.mod.shift);

#ifdef APPLE_STYLE_KEYS
                if (k.mod.command) {
                    set_cursor_pos(text.length());
                } else if (k.mod.alt) {
#else
                if (k.mod.alt) {
                    handled=false;
                    break;
                } else if (k.mod.command) {
#endif
                    bool prev_char=false;
                    int cc=cursor_pos;

                    while (cc<text.length()) {
                        bool ischar=_is_text_char(text[cc]);

                        if (prev_char && !ischar)
                            break;

                        prev_char=ischar;
                        cc++;
                    }

                    set_cursor_pos(cc);

                } else {
                    set_cursor_pos(get_cursor_pos()+1);
                }

                shift_selection_check_post(k.mod.shift);

            }
            break;
            case KEY_DELETE: {

                if (!editable)
                    break;

                if (k.mod.shift && !k.mod.command && !k.mod.alt) {
                    cut_text();
                    break;
                }

                if (selection.enabled) {
                    undo_text=text;
                    selection_delete();
                    break;
                }

                int text_len = text.length();

                if (cursor_pos==text_len)
                    break; // nothing to do

#ifdef APPLE_STYLE_KEYS
                if (k.mod.alt) {
#else
                if (k.mod.alt) {
                    handled=false;
                    break;
                } else if (k.mod.command) {
#endif
                    int cc=cursor_pos;

                    bool prev_char=false;

                    while (cc<text.length()) {

                        bool ischar=_is_text_char(text[cc]);

                        if (prev_char && !ischar)
                            break;
                        prev_char=ischar;
                        cc++;
                    }

                    delete_text(cursor_pos,cc);

                } else {
                    undo_text=text;
                    set_cursor_pos(cursor_pos+1);
                    delete_char();
                }

            }
            break;
            case KEY_KP_7: {
                if (k.unicode != 0) {
                    handled = false;
                    break;
                }
                // numlock disabled. fallthrough to key_home
            }
            case KEY_HOME: {

                shift_selection_check_pre(k.mod.shift);
                set_cursor_pos(0);
                shift_selection_check_post(k.mod.shift);
            }
            break;
            case KEY_KP_1: {
                if (k.unicode != 0) {
                    handled = false;
                    break;
                }
                // numlock disabled. fallthrough to key_end
            }
            case KEY_END: {

                shift_selection_check_pre(k.mod.shift);
                set_cursor_pos(text.length());
                shift_selection_check_post(k.mod.shift);
            }
            break;


            default: {

                handled=false;
            }
            break;
        }

        if (handled) {
            accept_event();
        } else if (!k.mod.alt && !k.mod.command) {
            if (k.unicode>=32 && k.scancode!=KEY_DELETE) {

                if (editable) {
                    selection_delete();
                    CharType ucodestr[2]= {(CharType)k.unicode,0};
                    append_at_cursor(ucodestr);
                    _text_changed();
                    accept_event();
                }

            } else {
                return;
            }
        }

        update();

    }


    return;

}
break;

    }
}

void LineEdit::set_align(Align p_align) {

ERR_FAIL_INDEX(p_align, 4);
align = p_align;
update();
}

LineEdit::Align LineEdit::get_align() const {

return align;
}

Variant LineEdit::get_drag_data(const Point2& p_point) {

if (selection.drag_attempt && selection.enabled) {
    String t = text.substr(selection.begin, selection.end - selection.begin);
    Label *l = memnew( Label );
    l->set_text(t);
    set_drag_preview(l);
    return 	t;
}

return Variant();

}
bool LineEdit::can_drop_data(const Point2& p_point,const Variant& p_data) const {

return p_data.get_type()==Variant::STRING;
}
void LineEdit::drop_data(const Point2& p_point,const Variant& p_data) {

if (p_data.get_type()==Variant::STRING) {
    set_cursor_at_pixel_pos(p_point.x);
    int selected = selection.end - selection.begin;

    Ref<Font> font = get_font("font");
    if (font != NULL) {
        for (int i = selection.begin; i < selection.end; i++)
            cached_width -= font->get_char_size(text[i]).width;
    }

    text.erase(selection.begin, selected);

    append_at_cursor(p_data);
    selection.begin = cursor_pos-selected;
    selection.end = cursor_pos;
}
}


void LineEdit::_notification(int p_what) {

switch(p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_ENTER_TREE: {
    if (get_tree()->is_editor_hint()) {
        cursor_set_blink_enabled(EDITOR_DEF("text_editor/caret_blink", false));
        cursor_set_blink_speed(EDITOR_DEF("text_editor/caret_blink_speed", 0.65));

        if (!EditorSettings::get_singleton()->is_connected("settings_changed",this,"_editor_settings_changed")) {
            EditorSettings::get_singleton()->connect("settings_changed",this,"_editor_settings_changed");
        }
    }
}
break;
#endif
case NOTIFICATION_RESIZED: {

    set_cursor_pos( get_cursor_pos() );

}
break;
case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
    window_has_focus = true;
    draw_caret = true;
    update();
}
break;
case MainLoop::NOTIFICATION_WM_FOCUS_OUT: {
    window_has_focus = false;
    draw_caret = false;
    update();
}
break;
case NOTIFICATION_DRAW: {

    if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
        draw_caret = false;
    }

    int width,height;

    Size2 size=get_size();
    width=size.width;
    height=size.height;

    RID ci = get_canvas_item();

    Ref<StyleBox> style = get_stylebox("normal");
    if (!is_editable())
        style=get_stylebox("read_only");

    Ref<Font> font=get_font("font");

    style->draw( ci, Rect2( Point2(), size ) );

    if (has_focus()) {

        get_stylebox("focus")->draw( ci, Rect2( Point2(), size ) );
    }

    int x_ofs=0;

    switch (align) {

    case ALIGN_FILL:
    case ALIGN_LEFT: {

        x_ofs=style->get_offset().x;
    }
    break;
    case ALIGN_CENTER: {

        x_ofs=int(size.width-(cached_width))/2;
    }
    break;
    case ALIGN_RIGHT: {

        x_ofs=int(size.width-style->get_offset().x-(cached_width));
    }
    break;
    }

    int ofs_max=width-style->get_minimum_size().width;
    int char_ofs=window_pos;

    int y_area=height-style->get_minimum_size().height;
    int y_ofs=style->get_offset().y;

    int font_ascent=font->get_ascent();

    Color selection_color=get_color("selection_color");
    Color font_color=get_color("font_color");
    Color font_color_selected=get_color("font_color_selected");
    Color cursor_color=get_color("cursor_color");

    const String& t = text.empty() ? placeholder : text;
    // draw placeholder color
    if(text.empty())
        font_color.a *= placeholder_alpha;

    int caret_height = font->get_height() > y_area ? y_area : font->get_height();
    while(true) {

        //end of string, break!
        if (char_ofs>=t.length())
            break;

        CharType cchar=pass?'*':t[char_ofs];
        CharType next=pass?'*':t[char_ofs+1];
        int char_width=font->get_char_size( cchar,next ).width;

        // end of widget, break!
        if ((x_ofs + char_width) > ofs_max)
            break;


        bool selected=selection.enabled && char_ofs>=selection.begin && char_ofs<selection.end;

        if (selected)
            VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, caret_height)), selection_color);


        font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);

        if (char_ofs==cursor_pos && draw_caret) {
            VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
                        Point2( x_ofs , y_ofs ), Size2( 1, caret_height ) ), cursor_color );
        }

        x_ofs+=char_width;
        char_ofs++;
    }

    if (char_ofs==cursor_pos && draw_caret) {//may be at the end
        VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(
                    Point2( x_ofs , y_ofs ), Size2( 1, caret_height ) ), cursor_color );
    }
}
break;
case NOTIFICATION_FOCUS_ENTER: {

    if (!caret_blink_enabled) {
        draw_caret = true;
    }

    if (OS::get_singleton()->has_virtual_keyboard())
        OS::get_singleton()->show_virtual_keyboard(text,get_global_rect());

}
break;
case NOTIFICATION_FOCUS_EXIT: {

    if (OS::get_singleton()->has_virtual_keyboard())
        OS::get_singleton()->hide_virtual_keyboard();

}
break;

}
}

void LineEdit::copy_text() {

if(selection.enabled) {

    OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
}
}

void LineEdit::cut_text() {

if(selection.enabled) {
    undo_text = text;
    OS::get_singleton()->set_clipboard(text.substr(selection.begin, selection.end - selection.begin));
    selection_delete();
}
}

void LineEdit::paste_text() {

String paste_buffer = OS::get_singleton()->get_clipboard();

if(paste_buffer != "") {

    if(selection.enabled) selection_delete();
    append_at_cursor(paste_buffer);

    _text_changed();
}



}

void LineEdit::undo() {

int old_cursor_pos = cursor_pos;
text = undo_text;

Ref<Font> font = get_font("font");

cached_width = 0;
for (int i = 0; i<text.length(); i++)
    cached_width += font->get_char_size(text[i]).width;

if(old_cursor_pos > text.length()) {
    set_cursor_pos(text.length());
} else {
    set_cursor_pos(old_cursor_pos);
}

_text_changed();
}
Пример #19
0
Vector3 Spatial::to_global(Vector3 p_local) const {

	return get_global_transform().xform(p_local);
}
Пример #20
0
Transform Camera::get_camera_transform() const {

	return get_global_transform();
}
Пример #21
0
Size2 Node2D::get_global_scale() const {

	return get_global_transform().get_scale();
}
Пример #22
0
Transform Listener::get_listener_transform() const {

	return get_global_transform().orthonormalized();
}
Пример #23
0
Point2 Node2D::to_local(Point2 p_global) const {

	return get_global_transform().affine_inverse().xform(p_global);
}
Пример #24
0
void Skeleton::_notification(int p_what) {

	switch (p_what) {

		case NOTIFICATION_ENTER_WORLD: {

			if (dirty) {

				dirty = false;
				_make_dirty(); // property make it dirty
			}

		} break;
		case NOTIFICATION_EXIT_WORLD: {

		} break;
		case NOTIFICATION_TRANSFORM_CHANGED: {

			if (dirty)
				break; //will be eventually updated

			//if moved, just update transforms
			VisualServer *vs = VisualServer::get_singleton();
			const Bone *bonesptr = bones.ptr();
			int len = bones.size();
			Transform global_transform = get_global_transform();
			Transform global_transform_inverse = global_transform.affine_inverse();

			for (int i = 0; i < len; i++) {

				const Bone &b = bonesptr[i];
				vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));
			}
		} break;
		case NOTIFICATION_UPDATE_SKELETON: {

			VisualServer *vs = VisualServer::get_singleton();
			Bone *bonesptr = bones.ptrw();
			int len = bones.size();

			vs->skeleton_allocate(skeleton, len); // if same size, nothin really happens

			// pose changed, rebuild cache of inverses
			if (rest_global_inverse_dirty) {

				// calculate global rests and invert them
				for (int i = 0; i < len; i++) {
					Bone &b = bonesptr[i];
					if (b.parent >= 0)
						b.rest_global_inverse = bonesptr[b.parent].rest_global_inverse * b.rest;
					else
						b.rest_global_inverse = b.rest;
				}
				for (int i = 0; i < len; i++) {
					Bone &b = bonesptr[i];
					b.rest_global_inverse.affine_invert();
				}

				rest_global_inverse_dirty = false;
			}

			Transform global_transform = get_global_transform();
			Transform global_transform_inverse = global_transform.affine_inverse();

			for (int i = 0; i < len; i++) {

				Bone &b = bonesptr[i];

				if (b.disable_rest) {
					if (b.enabled) {

						Transform pose = b.pose;
						if (b.custom_pose_enable) {

							pose = b.custom_pose * pose;
						}

						if (b.parent >= 0) {

							b.pose_global = bonesptr[b.parent].pose_global * pose;
						} else {

							b.pose_global = pose;
						}
					} else {

						if (b.parent >= 0) {

							b.pose_global = bonesptr[b.parent].pose_global;
						} else {

							b.pose_global = Transform();
						}
					}

				} else {
					if (b.enabled) {

						Transform pose = b.pose;
						if (b.custom_pose_enable) {

							pose = b.custom_pose * pose;
						}

						if (b.parent >= 0) {

							b.pose_global = bonesptr[b.parent].pose_global * (b.rest * pose);
						} else {

							b.pose_global = b.rest * pose;
						}
					} else {

						if (b.parent >= 0) {

							b.pose_global = bonesptr[b.parent].pose_global * b.rest;
						} else {

							b.pose_global = b.rest;
						}
					}
				}

				b.transform_final = b.pose_global * b.rest_global_inverse;
				vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));

				for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {

					Object *obj = ObjectDB::get_instance(E->get());
					ERR_CONTINUE(!obj);
					Spatial *sp = Object::cast_to<Spatial>(obj);
					ERR_CONTINUE(!sp);
					sp->set_transform(b.pose_global);
				}
			}

			dirty = false;
		} break;
	}
}
Пример #25
0
bool GridMap::_octant_update(const OctantKey &p_key) {
	ERR_FAIL_COND_V(!octant_map.has(p_key), false);
	Octant &g = *octant_map[p_key];
	if (!g.dirty)
		return false;

	//erase body shapes
	PhysicsServer::get_singleton()->body_clear_shapes(g.static_body);

	//erase body shapes debug
	if (g.collision_debug.is_valid()) {

		VS::get_singleton()->mesh_clear(g.collision_debug);
	}

	//erase navigation
	if (navigation) {
		for (Map<IndexKey, Octant::NavMesh>::Element *E = g.navmesh_ids.front(); E; E = E->next()) {
			navigation->navmesh_remove(E->get().id);
		}
		g.navmesh_ids.clear();
	}

	//erase multimeshes

	for (int i = 0; i < g.multimesh_instances.size(); i++) {

		VS::get_singleton()->free(g.multimesh_instances[i].instance);
		VS::get_singleton()->free(g.multimesh_instances[i].multimesh);
	}
	g.multimesh_instances.clear();

	if (g.cells.size() == 0) {
		//octant no longer needed
		_octant_clean_up(p_key);
		return true;
	}

	PoolVector<Vector3> col_debug;

	/*
	 * foreach item in this octant,
	 * set item's multimesh's instance count to number of cells which have this item
	 * and set said multimesh bounding box to one containing all cells which have this item
	 */

	Map<int, List<Pair<Transform, IndexKey> > > multimesh_items;

	for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) {

		ERR_CONTINUE(!cell_map.has(E->get()));
		const Cell &c = cell_map[E->get()];

		if (!theme.is_valid() || !theme->has_item(c.item))
			continue;

		//print_line("OCTANT, CELLS: "+itos(ii.cells.size()));

		Vector3 cellpos = Vector3(E->get().x, E->get().y, E->get().z);
		Vector3 ofs = _get_offset();

		Transform xform;

		if (clip && ((clip_above && cellpos[clip_axis] > clip_floor) || (!clip_above && cellpos[clip_axis] < clip_floor))) {

		} else {
		}

		xform.basis.set_orthogonal_index(c.rot);
		xform.set_origin(cellpos * cell_size + ofs);
		xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));

		if (theme->get_item_mesh(c.item).is_valid()) {
			if (!multimesh_items.has(c.item)) {
				multimesh_items[c.item] = List<Pair<Transform, IndexKey> >();
			}

			Pair<Transform, IndexKey> p;
			p.first = xform;
			p.second = E->get();
			multimesh_items[c.item].push_back(p);
		}

		Vector<MeshLibrary::ShapeData> shapes = theme->get_item_shapes(c.item);
		// add the item's shape at given xform to octant's static_body
		for (int i = 0; i < shapes.size(); i++) {
			// add the item's shape
			if (!shapes[i].shape.is_valid())
				continue;
			PhysicsServer::get_singleton()->body_add_shape(g.static_body, shapes[i].shape->get_rid(), xform * shapes[i].local_transform);
			if (g.collision_debug.is_valid()) {
				shapes[i].shape->add_vertices_to_array(col_debug, xform * shapes[i].local_transform);
			}

			//print_line("PHIS x: "+xform);
		}

		// add the item's navmesh at given xform to GridMap's Navigation ancestor
		Ref<NavigationMesh> navmesh = theme->get_item_navmesh(c.item);
		if (navmesh.is_valid()) {
			Octant::NavMesh nm;
			nm.xform = xform;

			if (navigation) {
				nm.id = navigation->navmesh_create(navmesh, xform, this);
			} else {
				nm.id = -1;
			}
			g.navmesh_ids[E->get()] = nm;
		}
	}

	//update multimeshes
	for (Map<int, List<Pair<Transform, IndexKey> > >::Element *E = multimesh_items.front(); E; E = E->next()) {
		Octant::MultimeshInstance mmi;

		RID mm = VS::get_singleton()->multimesh_create();
		VS::get_singleton()->multimesh_allocate(mm, E->get().size(), VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_NONE);
		VS::get_singleton()->multimesh_set_mesh(mm, theme->get_item_mesh(E->key())->get_rid());

		int idx = 0;
		for (List<Pair<Transform, IndexKey> >::Element *F = E->get().front(); F; F = F->next()) {
			VS::get_singleton()->multimesh_instance_set_transform(mm, idx, F->get().first);
#ifdef TOOLS_ENABLED

			Octant::MultimeshInstance::Item it;
			it.index = idx;
			it.transform = F->get().first;
			it.key = F->get().second;
			mmi.items.push_back(it);
#endif

			idx++;
		}

		RID instance = VS::get_singleton()->instance_create();
		VS::get_singleton()->instance_set_base(instance, mm);

		if (is_inside_tree()) {
			VS::get_singleton()->instance_set_scenario(instance, get_world()->get_scenario());
			VS::get_singleton()->instance_set_transform(instance, get_global_transform());
		}

		mmi.multimesh = mm;
		mmi.instance = instance;

		g.multimesh_instances.push_back(mmi);
	}

	if (col_debug.size()) {

		Array arr;
		arr.resize(VS::ARRAY_MAX);
		arr[VS::ARRAY_VERTEX] = col_debug;

		VS::get_singleton()->mesh_add_surface_from_arrays(g.collision_debug, VS::PRIMITIVE_LINES, arr);
		SceneTree *st = SceneTree::get_singleton();
		if (st) {
			VS::get_singleton()->mesh_surface_set_material(g.collision_debug, 0, st->get_debug_collision_material()->get_rid());
		}
	}

	g.dirty = false;

	return false;
}
Пример #26
0
Transform Spatial::get_global_gizmo_transform() const {
	return get_global_transform();
}
Пример #27
0
Point2 Node2D::get_global_pos() const {

	return get_global_transform().get_origin();
}
Пример #28
0
void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) {

	Transform t = get_global_transform();
	t.basis.rotate(p_axis, p_angle);
	set_global_transform(t);
}
Пример #29
0
Vector2 KinematicBody2D::move(const Vector2& p_motion) {

	//give me back regular physics engine logic
	//this is madness
	//and most people using this function will think
	//what it does is simpler than using physics
	//this took about a week to get right..
	//but is it right? who knows at this point..


	colliding=false;
	ERR_FAIL_COND_V(!is_inside_tree(),Vector2());
	Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space());
	ERR_FAIL_COND_V(!dss,Vector2());
	const int max_shapes=32;
	Vector2 sr[max_shapes*2];
	int res_shapes;

	Set<RID> exclude;
	exclude.insert(get_rid());


	//recover first
	int recover_attempts=4;

	bool collided=false;
	uint32_t mask=0;
	if (collide_static)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_STATIC_BODY;
	if (collide_kinematic)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_KINEMATIC_BODY;
	if (collide_rigid)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_RIGID_BODY;
	if (collide_character)
		mask|=Physics2DDirectSpaceState::TYPE_MASK_CHARACTER_BODY;

//	print_line("motion: "+p_motion+" margin: "+rtos(margin));

	//print_line("margin: "+rtos(margin));
	do {

		//motion recover
		for(int i=0;i<get_shape_count();i++) {

			if (is_shape_set_as_trigger(i))
				continue;
			if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask))
				collided=true;

		}

		if (!collided)
			break;

		Vector2 recover_motion;

		for(int i=0;i<res_shapes;i++) {

			Vector2 a = sr[i*2+0];
			Vector2 b = sr[i*2+1];

			float d = a.distance_to(b);

			//if (d<margin)
			///	continue;
			recover_motion+=(b-a)*0.2;
		}

		if (recover_motion==Vector2()) {
			collided=false;
			break;
		}

		Matrix32 gt = get_global_transform();
		gt.elements[2]+=recover_motion;
		set_global_transform(gt);

		recover_attempts--;

	} while (recover_attempts);


	//move second
	float safe = 1.0;
	float unsafe = 1.0;
	int best_shape=-1;

	for(int i=0;i<get_shape_count();i++) {

		if (is_shape_set_as_trigger(i))
			continue;

		float lsafe,lunsafe;
		bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask);
		//print_line("shape: "+itos(i)+" travel:"+rtos(ltravel));
		if (!valid) {
			safe=0;
			unsafe=0;
			best_shape=i; //sadly it's the best
			break;
		}
		if (lsafe==1.0) {
			continue;
		}
		if (lsafe < safe) {

			safe=lsafe;
			unsafe=lunsafe;
			best_shape=i;
		}
	}


	//print_line("best shape: "+itos(best_shape)+" motion "+p_motion);

	if (safe>=1) {
		//not collided
		colliding=false;
	} else {

		//it collided, let's get the rest info in unsafe advance
		Matrix32 ugt = get_global_transform();
		ugt.elements[2]+=p_motion*unsafe;
		Physics2DDirectSpaceState::ShapeRestInfo rest_info;
		bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask);
		if (!c2) {
			//should not happen, but floating point precision is so weird..
			colliding=false;
		} else {

			//print_line("Travel: "+rtos(travel));
			colliding=true;
			collision=rest_info.point;
			normal=rest_info.normal;
			collider=rest_info.collider_id;
			collider_vel=rest_info.linear_velocity;
			collider_shape=rest_info.shape;
			collider_metadata=rest_info.metadata;
		}

	}

	Vector2 motion=p_motion*safe;
	Matrix32 gt = get_global_transform();
	gt.elements[2]+=motion;
	set_global_transform(gt);

	return p_motion-motion;

}
Пример #30
0
Transform Camera::get_camera_transform() const {

	return get_global_transform().orthonormalized();
}