RID DampedSpringJoint2D::_configure_joint(){ Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL; if (!node_a || !node_b) return RID(); PhysicsBody2D *body_a=node_a->cast_to<PhysicsBody2D>(); PhysicsBody2D *body_b=node_b->cast_to<PhysicsBody2D>(); if (!body_a || !body_b) return RID(); if (get_exclude_nodes_from_collision()) Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); else Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(),body_b->get_rid()); Matrix32 gt = get_global_transform(); Vector2 anchor_A = gt.get_origin(); Vector2 anchor_B = gt.xform( Vector2(0,length) ); RID dsj = Physics2DServer::get_singleton()->damped_spring_joint_create(anchor_A,anchor_B,body_a->get_rid(),body_b->get_rid()); if (rest_length) Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_REST_LENGTH,rest_length); Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_STIFFNESS,stiffness); Physics2DServer::get_singleton()->damped_string_joint_set_param(dsj,Physics2DServer::DAMPED_STRING_DAMPING,damping); return dsj; }
RID PinJoint2D::_configure_joint() { Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL; if (!node_a && !node_b) return RID(); PhysicsBody2D *body_a=node_a ? node_a->cast_to<PhysicsBody2D>() : (PhysicsBody2D*)NULL; PhysicsBody2D *body_b=node_b ? node_b->cast_to<PhysicsBody2D>() : (PhysicsBody2D*)NULL; if (!body_a && !body_b) return RID(); if (!body_a) { SWAP(body_a,body_b); } else if (body_b) { //add a collision exception between both if (get_exclude_nodes_from_collision()) Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); else Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(),body_b->get_rid()); } RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID()); Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness); return pj; }
RID GrooveJoint2D::_configure_joint(){ Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; Node *node_b = has_node( get_node_b() ) ? get_node( get_node_b() ) : (Node*)NULL; if (!node_a || !node_b) return RID(); PhysicsBody2D *body_a=node_a->cast_to<PhysicsBody2D>(); PhysicsBody2D *body_b=node_b->cast_to<PhysicsBody2D>(); if (!body_a || !body_b) return RID(); if (get_exclude_nodes_from_collision()) Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); else Physics2DServer::get_singleton()->body_remove_collision_exception(body_a->get_rid(),body_b->get_rid()); Matrix32 gt = get_global_transform(); Vector2 groove_A1 = gt.get_origin(); Vector2 groove_A2 = gt.xform( Vector2(0,length) ); Vector2 anchor_B = gt.xform( Vector2(0,initial_offset) ); return Physics2DServer::get_singleton()->groove_joint_create(groove_A1,groove_A2,anchor_B,body_a->get_rid(),body_b->get_rid()); }
void SoftBody::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path) { SoftBody::PinnedPoint *pinned_point; if (-1 == _get_pinned_point(p_point_index, pinned_point)) { // Create new PinnedPoint pp; pp.point_index = p_point_index; pp.spatial_attachment_path = p_spatial_attachment_path; if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) { pp.spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path)); pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index)); } pinned_points.push_back(pp); } else { pinned_point->point_index = p_point_index; pinned_point->spatial_attachment_path = p_spatial_attachment_path; if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) { pinned_point->spatial_attachment = Object::cast_to<Spatial>(get_node(p_spatial_attachment_path)); pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index)); } } }
void graph_t::remove_dependency( node_t *s, node_t *d) { RAMEN_ASSERT( s != d); if( has_node( s) && has_node( d)) { vertex_desc_type vs = node_to_desc_[s]; vertex_desc_type vd = node_to_desc_[d]; boost::remove_edge( vs, vd, graph_); valid_order_ = false; } }
void AttackNode::update_attack_area() { if (is_inside_tree() && attack_area_path != String("") && has_node(attack_area_path)) { attack_area = get_node(attack_area_path)->cast_to<AttackArea>(); }else { attack_area = NULL; } }
void SceneTreeEditor::_update_selection(TreeItem *item) { ERR_FAIL_COND(!item); NodePath np = item->get_metadata(0); if (!has_node(np)) return; Node *n=get_node(np); if (!n) return; if (editor_selection->is_selected(n)) item->select(0); else item->deselect(0); TreeItem *c=item->get_children(); while(c) { _update_selection(c); c=c->get_next(); } }
void ScrollBar::set_drag_slave(const NodePath &p_path) { if (is_inside_tree()) { if (drag_slave) { drag_slave->disconnect("gui_input", this, "_drag_slave_input"); drag_slave->disconnect("tree_exited", this, "_drag_slave_exit"); } } drag_slave = NULL; drag_slave_path = p_path; if (is_inside_tree()) { if (has_node(p_path)) { Node *n = get_node(p_path); drag_slave = n->cast_to<Control>(); } if (drag_slave) { drag_slave->connect("gui_input", this, "_drag_slave_input"); drag_slave->connect("tree_exited", this, "_drag_slave_exit", varray(), CONNECT_ONESHOT); } } }
void LinkerBNode::update_link_path() { if (is_inside_tree() && link_path != NodePath() && has_node(link_path)) { link_target = get_node(link_path)->cast_to<BehaviorNode>(); }else { link_target = NULL; } }
String ParticleAttractor2D::get_configuration_warning() const { if (!has_node(path) || !get_node(path) || !get_node(path)->cast_to<Particles2D>()) { return TTR("Path property must point to a valid Particles2D node to work."); } return String(); }
boost::filesystem::path add_node(T const &key) { assert(not has_node(key)); typename graph_type::vertex_descriptor v = boost::add_vertex(graph_); mapping_[key] = v; boost::put(boost::vertex_name_t(), graph_, v, key); return key; }
String RemoteTransform2D::get_configuration_warning() const { if (!has_node(remote_node) || !Object::cast_to<Node2D>(get_node(remote_node))) { return TTR("Path property must point to a valid Node2D node to work."); } return String(); }
String RemoteTransform::get_configuration_warning() const { if (!has_node(remote_node) || !get_node(remote_node) || !get_node(remote_node)->cast_to<Spatial>()) { return TTR("Path property must point to a valid Spatial node to work."); } return String(); }
void graph_t::add_node( node_t *v) { RAMEN_ASSERT( !has_node( v)); vertex_desc_type vd = boost::add_vertex( graph_); graph_[vd].node = v; node_to_desc_[v] = vd; valid_order_ = false; }
void graph_t::add_dependency( node_t *s, node_t *d) { RAMEN_ASSERT( has_node( s) && has_node( d)); RAMEN_ASSERT( s != d); boost::add_edge( node_to_desc_[s], node_to_desc_[d], graph_); cycle_detector v; boost::depth_first_search( graph_, boost::visitor( v)); if( v.has_cycle) { remove_dependency( s, d); throw cycle_error(); } valid_order_ = false; }
void graph_t::remove_node( node_t *v) { RAMEN_ASSERT( has_node( v)); vertex_desc_type vd = node_to_desc_[v]; boost::clear_vertex( vd, graph_); boost::remove_vertex( vd, graph_); node_to_desc_.erase( v); valid_order_ = false; }
void Joint2D::_update_joint(bool p_only_free) { if (joint.is_valid()) { if (ba.is_valid() && bb.is_valid()) Physics2DServer::get_singleton()->body_remove_collision_exception(ba, bb); Physics2DServer::get_singleton()->free(joint); joint = RID(); ba = RID(); bb = RID(); } if (p_only_free || !is_inside_tree()) return; Node *node_a = has_node(get_node_a()) ? get_node(get_node_a()) : (Node *)NULL; Node *node_b = has_node(get_node_b()) ? get_node(get_node_b()) : (Node *)NULL; if (!node_a || !node_b) return; PhysicsBody2D *body_a = Object::cast_to<PhysicsBody2D>(node_a); PhysicsBody2D *body_b = Object::cast_to<PhysicsBody2D>(node_b); if (!body_a || !body_b) return; if (!body_a) { SWAP(body_a, body_b); } joint = _configure_joint(body_a, body_b); if (!joint.is_valid()) return; Physics2DServer::get_singleton()->get_singleton()->joint_set_param(joint, Physics2DServer::JOINT_PARAM_BIAS, bias); ba = body_a->get_rid(); bb = body_b->get_rid(); Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision); }
void RemoteTransform::_update_cache() { cache=0; if (has_node(remote_node)) { Node *node = get_node(remote_node); if (!node || this==node || node->is_a_parent_of(this) || this->is_a_parent_of(node)) { return; } cache=node->get_instance_ID(); } }
void InterpolatedCamera::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_SCENE: { if (get_scene()->is_editor_hint() && enabled) set_fixed_process(false); } break; case NOTIFICATION_PROCESS: { if (!enabled) break; if (has_node(target)) { Spatial *node = get_node(target)->cast_to<Spatial>(); if (!node) break; float delta = speed*get_process_delta_time(); Transform target_xform = node->get_global_transform(); Transform local_transform = get_transform(); local_transform = local_transform.interpolate_with(target_xform,delta); set_global_transform(local_transform); if (node->cast_to<Camera>()) { Camera *cam = node->cast_to<Camera>(); if (cam->get_projection()==get_projection()) { float new_near = Math::lerp(get_znear(),cam->get_znear(),delta); float new_far = Math::lerp(get_zfar(),cam->get_zfar(),delta); if (cam->get_projection()==PROJECTION_ORTHOGONAL) { float size = Math::lerp(get_size(),cam->get_size(),delta); set_orthogonal(size,new_near,new_far); } else { float fov = Math::lerp(get_fov(),cam->get_fov(),delta); set_perspective(fov,new_near,new_far); } } } } } break; } }
void place_apple(void) { int x; int y; do { x = ARENA_START + 1 + (rand() % (ARENA_SIZE - 1)); y = ARENA_START + 1 + (rand() % (ARENA_SIZE - 1)); } while (has_node(x, y)); f_state.apple.x = x; f_state.apple.y = y; h3m_object_move(f_state.h3m, f_state.apple.od_index, f_state.apple.x, f_state.apple.y, 0); }
void ParticleAttractor2D::_update_owner() { if (!is_inside_tree() || !has_node(path)) { _set_owner(NULL); return; } Node *n = get_node(path); ERR_FAIL_COND(!n); Particles2D *pn = n->cast_to<Particles2D>(); if (!pn) { _set_owner(NULL); return; } _set_owner(pn); }
String AnimationTree::get_configuration_warning() const { String warning = Node::get_configuration_warning(); if (!root.is_valid()) { if (warning != String()) { warning += "\n"; } warning += TTR("A root AnimationNode for the graph is not set."); } if (!has_node(animation_player)) { if (warning != String()) { warning += "\n"; } warning += TTR("Path to an AnimationPlayer node containing animations is not set."); return warning; } AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); if (!player) { if (warning != String()) { warning += "\n"; } warning += TTR("Path set for AnimationPlayer does not lead to an AnimationPlayer node."); return warning; } if (!player->has_node(player->get_root())) { if (warning != String()) { warning += "\n"; } warning += TTR("AnimationPlayer root is not a valid node."); return warning; } return warning; }
String ViewportSprite::get_configuration_warning() const { if (!has_node(viewport_path) || !get_node(viewport_path) || !get_node(viewport_path)->cast_to<Viewport>()) { return TTR("Path property must point to a valid Viewport node to work. Such Viewport must be set to 'render target' mode."); } else { Node *n = get_node(viewport_path); if (n) { Viewport *vp = n->cast_to<Viewport>(); if (!vp->is_set_as_render_target()) { return TTR("The Viewport set in the path property must be set as 'render target' in order for this sprite to work."); } } } return String(); }
bool Node::has_node_and_resource(const NodePath& p_path) const { if (!has_node(p_path)) return false; Node *node = get_node(p_path); if (p_path.get_subname_count()) { RES r; for(int j=0;j<p_path.get_subname_count();j++) { r = j==0 ? node->get(p_path.get_subname(j)) : r->get(p_path.get_subname(j)); if (r.is_null()) return false; } } return true; }
/** Remove a node from the graph. * @param[in] n Node to be removed * @return 1 if old has_node(n), 0 otherwise * * @post new size() == old size() - result. * * Can invalidate outstanding iterators. * If old has_node(@a n), then @a n becomes invalid, as do any * other Node objects equal to @a n. All other Node objects remain valid. * * Complexity: O(i2u_edges_[i].size()^2) */ size_type remove_node ( const Node & n){ if( !has_node(n) ) return 0; idx_type idx = n.index(); size_type uid = i2u_nodes_[idx]; assert( internal_nodes_[ i2u_nodes_[idx] ].idx == idx ); // Remove all incident edges before the node is removed. idx_type x = 0; adj_list_valid_edges v = i2u_edges_[idx]; while(x < v.size()){ // uid of each element in v size_type v_uid = v[x]; adj_list_valid_edges adj = i2u_edges_[ internal_nodes_[v_uid].idx ]; for(size_type adj_uid : adj) if(adj_uid == uid){ remove_edge(Node(this, v_uid), Node(this, adj_uid)); } ++x; } // Remove the vector from i2i_edges, so i2u_nodes and i2i_edges are in sync by idx i2u_edges_.erase(i2u_edges_.begin() + idx); // Remove the uid from the list of valid nodes i2u_nodes_.erase(i2u_nodes_.begin() + idx); // Update the idxs for all nodes subsequent to the removed node x = idx; while(x < i2u_nodes_.size()){ internal_nodes_[ i2u_nodes_[x] ].idx = x; ++x; } return 1; }
int _update_nodes(int x_inc, int y_inc) { struct NODE *n = NULL; int i = 0; int od_index = 0; int x_new = f_state.head->x + x_inc; int y_new = f_state.head->y + y_inc; if (has_node(x_new, y_new) || x_new < ARENA_START + 1 || y_new < ARENA_START + 1 || x_new >= ARENA_START + ARENA_SIZE || y_new >= ARENA_START + ARENA_SIZE) { return 1; } if (f_state.node_count >= f_state.size) { _new_head(f_state.tail, x_new, y_new); f_state.tail = f_state.tail->next; h3m_object_move(f_state.h3m, f_state.head->od_index, f_state.head->x, f_state.head->y, 0); } else { n = calloc(1, sizeof(*n)); _new_head(n, x_new, y_new); ++f_state.node_count; h3m_object_add(f_state.h3m, "Serpent Fly", n->x, n->y, 0, &n->od_index); } if (has_apple(x_new, y_new)) { place_apple(); place_caged(); ++f_state.score; ++f_state.size; } return 0; }
void AnimationTree::_process_graph(float p_delta) { _update_properties(); //if properties need updating, update them //check all tracks, see if they need modification root_motion_transform = Transform(); if (!root.is_valid()) { ERR_PRINT("AnimationTree: root AnimationNode is not set, disabling playback."); set_active(false); cache_valid = false; return; } if (!has_node(animation_player)) { ERR_PRINT("AnimationTree: no valid AnimationPlayer path set, disabling playback"); set_active(false); cache_valid = false; return; } AnimationPlayer *player = Object::cast_to<AnimationPlayer>(get_node(animation_player)); ObjectID current_animation_player = 0; if (player) { current_animation_player = player->get_instance_id(); } if (last_animation_player != current_animation_player) { if (last_animation_player) { Object *old_player = ObjectDB::get_instance(last_animation_player); if (old_player) { old_player->disconnect("caches_cleared", this, "_clear_caches"); } } if (player) { player->connect("caches_cleared", this, "_clear_caches"); } last_animation_player = current_animation_player; } if (!player) { ERR_PRINT("AnimationTree: path points to a node not an AnimationPlayer, disabling playback"); set_active(false); cache_valid = false; return; } if (!cache_valid) { if (!_update_caches(player)) { return; } } { //setup process_pass++; state.valid = true; state.invalid_reasons = ""; state.animation_states.clear(); //will need to be re-created state.valid = true; state.player = player; state.last_pass = process_pass; state.tree = this; // root source blends root->blends.resize(state.track_count); float *src_blendsw = root->blends.ptrw(); for (int i = 0; i < state.track_count; i++) { src_blendsw[i] = 1.0; //by default all go to 1 for the root input } } //process { if (started) { //if started, seek root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, 0, true, Vector<StringName>()); started = false; } root->_pre_process(SceneStringNames::get_singleton()->parameters_base_path, NULL, &state, p_delta, false, Vector<StringName>()); } if (!state.valid) { return; //state is not valid. do nothing. } //apply value/transform/bezier blends to track caches and execute method/audio/animation tracks { bool can_call = is_inside_tree() && !Engine::get_singleton()->is_editor_hint(); for (List<AnimationNode::AnimationState>::Element *E = state.animation_states.front(); E; E = E->next()) { const AnimationNode::AnimationState &as = E->get(); Ref<Animation> a = as.animation; float time = as.time; float delta = as.delta; bool seeked = as.seeked; for (int i = 0; i < a->get_track_count(); i++) { NodePath path = a->track_get_path(i); ERR_CONTINUE(!track_cache.has(path)); TrackCache *track = track_cache[path]; if (track->type != a->track_get_type(i)) { continue; //may happen should not } track->root_motion = root_motion_track == path; ERR_CONTINUE(!state.track_map.has(path)); int blend_idx = state.track_map[path]; ERR_CONTINUE(blend_idx < 0 || blend_idx >= state.track_count); float blend = (*as.track_blends)[blend_idx]; if (blend < CMP_EPSILON) continue; //nothing to blend switch (track->type) { case Animation::TYPE_TRANSFORM: { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); if (track->root_motion) { if (t->process_pass != process_pass) { t->process_pass = process_pass; t->loc = Vector3(); t->rot = Quat(); t->rot_blend_accum = 0; t->scale = Vector3(1, 1, 1); } float prev_time = time - delta; if (prev_time < 0) { if (!a->has_loop()) { prev_time = 0; } else { prev_time = a->get_length() + prev_time; } } Vector3 loc[2]; Quat rot[2]; Vector3 scale[2]; if (prev_time > time) { Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); if (err != OK) { continue; } a->transform_track_interpolate(i, a->get_length(), &loc[1], &rot[1], &scale[1]); t->loc += (loc[1] - loc[0]) * blend; t->scale += (scale[1] - scale[0]) * blend; Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } Error err = a->transform_track_interpolate(i, prev_time, &loc[0], &rot[0], &scale[0]); if (err != OK) { continue; } a->transform_track_interpolate(i, time, &loc[1], &rot[1], &scale[1]); t->loc += (loc[1] - loc[0]) * blend; t->scale += (scale[1] - scale[0]) * blend; Quat q = Quat().slerp(rot[0].normalized().inverse() * rot[1].normalized(), blend).normalized(); t->rot = (t->rot * q).normalized(); prev_time = 0; } else { Vector3 loc; Quat rot; Vector3 scale; Error err = a->transform_track_interpolate(i, time, &loc, &rot, &scale); //ERR_CONTINUE(err!=OK); //used for testing, should be removed if (t->process_pass != process_pass) { t->process_pass = process_pass; t->loc = loc; t->rot = rot; t->rot_blend_accum = 0; t->scale = scale; } if (err != OK) continue; t->loc = t->loc.linear_interpolate(loc, blend); if (t->rot_blend_accum == 0) { t->rot = rot; t->rot_blend_accum = blend; } else { float rot_total = t->rot_blend_accum + blend; t->rot = rot.slerp(t->rot, t->rot_blend_accum / rot_total).normalized(); t->rot_blend_accum = rot_total; } t->scale = t->scale.linear_interpolate(scale, blend); } } break; case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); Animation::UpdateMode update_mode = a->value_track_get_update_mode(i); if (update_mode == Animation::UPDATE_CONTINUOUS || update_mode == Animation::UPDATE_CAPTURE) { //delta == 0 means seek Variant value = a->value_track_interpolate(i, time); if (value == Variant()) continue; if (t->process_pass != process_pass) { t->value = value; t->process_pass = process_pass; } Variant::interpolate(t->value, value, blend, t->value); } else if (delta != 0) { List<int> indices; a->value_track_get_key_indices(i, time, delta, &indices); for (List<int>::Element *F = indices.front(); F; F = F->next()) { Variant value = a->track_get_key_value(i, F->get()); t->object->set_indexed(t->subpath, value); } } } break; case Animation::TYPE_METHOD: { if (delta == 0) { continue; } TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track); List<int> indices; a->method_track_get_key_indices(i, time, delta, &indices); for (List<int>::Element *F = indices.front(); F; F = F->next()) { StringName method = a->method_track_get_name(i, F->get()); Vector<Variant> params = a->method_track_get_params(i, F->get()); int s = params.size(); ERR_CONTINUE(s > VARIANT_ARG_MAX); if (can_call) { t->object->call_deferred( method, s >= 1 ? params[0] : Variant(), s >= 2 ? params[1] : Variant(), s >= 3 ? params[2] : Variant(), s >= 4 ? params[3] : Variant(), s >= 5 ? params[4] : Variant()); } } } break; case Animation::TYPE_BEZIER: { TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); float bezier = a->bezier_track_interpolate(i, time); if (t->process_pass != process_pass) { t->value = bezier; t->process_pass = process_pass; } t->value = Math::lerp(t->value, bezier, blend); } break; case Animation::TYPE_AUDIO: { TrackCacheAudio *t = static_cast<TrackCacheAudio *>(track); if (seeked) { //find whathever should be playing int idx = a->track_find_key(i, time); if (idx < 0) continue; Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx); if (!stream.is_valid()) { t->object->call("stop"); t->playing = false; playing_caches.erase(t); } else { float start_ofs = a->audio_track_get_key_start_offset(i, idx); start_ofs += time - a->track_get_key_time(i, idx); float end_ofs = a->audio_track_get_key_end_offset(i, idx); float len = stream->get_length(); if (start_ofs > len - end_ofs) { t->object->call("stop"); t->playing = false; playing_caches.erase(t); continue; } t->object->call("set_stream", stream); t->object->call("play", start_ofs); t->playing = true; playing_caches.insert(t); if (len && end_ofs > 0) { //force a end at a time t->len = len - start_ofs - end_ofs; } else { t->len = 0; } t->start = time; } } else { //find stuff to play List<int> to_play; a->track_get_key_indices_in_range(i, time, delta, &to_play); if (to_play.size()) { int idx = to_play.back()->get(); Ref<AudioStream> stream = a->audio_track_get_key_stream(i, idx); if (!stream.is_valid()) { t->object->call("stop"); t->playing = false; playing_caches.erase(t); } else { float start_ofs = a->audio_track_get_key_start_offset(i, idx); float end_ofs = a->audio_track_get_key_end_offset(i, idx); float len = stream->get_length(); t->object->call("set_stream", stream); t->object->call("play", start_ofs); t->playing = true; playing_caches.insert(t); if (len && end_ofs > 0) { //force a end at a time t->len = len - start_ofs - end_ofs; } else { t->len = 0; } t->start = time; } } else if (t->playing) { bool loop = a->has_loop(); bool stop = false; if (!loop && time < t->start) { stop = true; } else if (t->len > 0) { float len = t->start > time ? (a->get_length() - t->start) + time : time - t->start; if (len > t->len) { stop = true; } } if (stop) { //time to stop t->object->call("stop"); t->playing = false; playing_caches.erase(t); } } } float db = Math::linear2db(MAX(blend, 0.00001)); if (t->object->has_method("set_unit_db")) { t->object->call("set_unit_db", db); } else { t->object->call("set_volume_db", db); } } break; case Animation::TYPE_ANIMATION: { TrackCacheAnimation *t = static_cast<TrackCacheAnimation *>(track); AnimationPlayer *player2 = Object::cast_to<AnimationPlayer>(t->object); if (!player2) continue; if (delta == 0 || seeked) { //seek int idx = a->track_find_key(i, time); if (idx < 0) continue; float pos = a->track_get_key_time(i, idx); StringName anim_name = a->animation_track_get_key_animation(i, idx); if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) continue; Ref<Animation> anim = player2->get_animation(anim_name); float at_anim_pos; if (anim->has_loop()) { at_anim_pos = Math::fposmod(time - pos, anim->get_length()); //seek to loop } else { at_anim_pos = MAX(anim->get_length(), time - pos); //seek to end } if (player2->is_playing() || seeked) { player2->play(anim_name); player2->seek(at_anim_pos); t->playing = true; playing_caches.insert(t); } else { player2->set_assigned_animation(anim_name); player2->seek(at_anim_pos, true); } } else { //find stuff to play List<int> to_play; a->track_get_key_indices_in_range(i, time, delta, &to_play); if (to_play.size()) { int idx = to_play.back()->get(); StringName anim_name = a->animation_track_get_key_animation(i, idx); if (String(anim_name) == "[stop]" || !player2->has_animation(anim_name)) { if (playing_caches.has(t)) { playing_caches.erase(t); player2->stop(); t->playing = false; } } else { player2->play(anim_name); t->playing = true; playing_caches.insert(t); } } } } break; } } } } { // finally, set the tracks const NodePath *K = NULL; while ((K = track_cache.next(K))) { TrackCache *track = track_cache[*K]; if (track->process_pass != process_pass) continue; //not processed, ignore switch (track->type) { case Animation::TYPE_TRANSFORM: { TrackCacheTransform *t = static_cast<TrackCacheTransform *>(track); Transform xform; xform.origin = t->loc; xform.basis.set_quat_scale(t->rot, t->scale); if (t->root_motion) { root_motion_transform = xform; if (t->skeleton && t->bone_idx >= 0) { root_motion_transform = (t->skeleton->get_bone_rest(t->bone_idx) * root_motion_transform) * t->skeleton->get_bone_rest(t->bone_idx).affine_inverse(); } } else if (t->skeleton && t->bone_idx >= 0) { t->skeleton->set_bone_pose(t->bone_idx, xform); } else { t->spatial->set_transform(xform); } } break; case Animation::TYPE_VALUE: { TrackCacheValue *t = static_cast<TrackCacheValue *>(track); t->object->set_indexed(t->subpath, t->value); } break; case Animation::TYPE_BEZIER: { TrackCacheBezier *t = static_cast<TrackCacheBezier *>(track); t->object->set_indexed(t->subpath, t->value); } break; default: { } //the rest don't matter } } } }
void Polygon2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { if (polygon.size() < 3) return; Skeleton2D *skeleton_node = NULL; if (has_node(skeleton)) { skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton)); } ObjectID new_skeleton_id = 0; if (skeleton_node) { VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton()); new_skeleton_id = skeleton_node->get_instance_id(); } else { VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID()); } if (new_skeleton_id != current_skeleton_id) { Object *old_skeleton = ObjectDB::get_instance(current_skeleton_id); if (old_skeleton) { old_skeleton->disconnect("bone_setup_changed", this, "_skeleton_bone_setup_changed"); } if (skeleton_node) { skeleton_node->connect("bone_setup_changed", this, "_skeleton_bone_setup_changed"); } current_skeleton_id = new_skeleton_id; } Vector<Vector2> points; Vector<Vector2> uvs; Vector<int> bones; Vector<float> weights; int len = polygon.size(); if ((invert || polygons.size() == 0) && internal_vertices > 0) { //if no polygons are around, internal vertices must not be drawn, else let them be len -= internal_vertices; } if (len <= 0) { return; } points.resize(len); { PoolVector<Vector2>::Read polyr = polygon.read(); for (int i = 0; i < len; i++) { points.write[i] = polyr[i] + offset; } } if (invert) { Rect2 bounds; int highest_idx = -1; float highest_y = -1e20; float sum = 0; for (int i = 0; i < len; i++) { if (i == 0) bounds.position = points[i]; else bounds.expand_to(points[i]); if (points[i].y > highest_y) { highest_idx = i; highest_y = points[i].y; } int ni = (i + 1) % len; sum += (points[ni].x - points[i].x) * (points[ni].y + points[i].y); } bounds = bounds.grow(invert_border); Vector2 ep[7] = { Vector2(points[highest_idx].x, points[highest_idx].y + invert_border), Vector2(bounds.position + bounds.size), Vector2(bounds.position + Vector2(bounds.size.x, 0)), Vector2(bounds.position), Vector2(bounds.position + Vector2(0, bounds.size.y)), Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y + invert_border), Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y), }; if (sum > 0) { SWAP(ep[1], ep[4]); SWAP(ep[2], ep[3]); SWAP(ep[5], ep[0]); SWAP(ep[6], points.write[highest_idx]); } points.resize(points.size() + 7); for (int i = points.size() - 1; i >= highest_idx + 7; i--) { points.write[i] = points[i - 7]; } for (int i = 0; i < 7; i++) { points.write[highest_idx + i + 1] = ep[i]; } len = points.size(); } if (texture.is_valid()) { Transform2D texmat(tex_rot, tex_ofs); texmat.scale(tex_scale); Size2 tex_size = texture->get_size(); uvs.resize(len); if (points.size() == uv.size()) { PoolVector<Vector2>::Read uvr = uv.read(); for (int i = 0; i < len; i++) { uvs.write[i] = texmat.xform(uvr[i]) / tex_size; } } else { for (int i = 0; i < len; i++) { uvs.write[i] = texmat.xform(points[i]) / tex_size; } } } if (skeleton_node && !invert && bone_weights.size()) { //a skeleton is set! fill indices and weights int vc = len; bones.resize(vc * 4); weights.resize(vc * 4); int *bonesw = bones.ptrw(); float *weightsw = weights.ptrw(); for (int i = 0; i < vc * 4; i++) { bonesw[i] = 0; weightsw[i] = 0; } for (int i = 0; i < bone_weights.size(); i++) { if (bone_weights[i].weights.size() != points.size()) { continue; //different number of vertices, sorry not using. } if (!skeleton_node->has_node(bone_weights[i].path)) { continue; //node does not exist } Bone2D *bone = Object::cast_to<Bone2D>(skeleton_node->get_node(bone_weights[i].path)); if (!bone) { continue; } int bone_index = bone->get_index_in_skeleton(); PoolVector<float>::Read r = bone_weights[i].weights.read(); for (int j = 0; j < vc; j++) { if (r[j] == 0.0) continue; //weight is unpainted, skip //find an index with a weight for (int k = 0; k < 4; k++) { if (weightsw[j * 4 + k] < r[j]) { //this is less than this weight, insert weight! for (int l = 3; l > k; l--) { weightsw[j * 4 + l] = weightsw[j * 4 + l - 1]; bonesw[j * 4 + l] = bonesw[j * 4 + l - 1]; } weightsw[j * 4 + k] = r[j]; bonesw[j * 4 + k] = bone_index; break; } } } } //normalize the weights for (int i = 0; i < vc; i++) { float tw = 0; for (int j = 0; j < 4; j++) { tw += weightsw[i * 4 + j]; } if (tw == 0) continue; //unpainted, do nothing //normalize for (int j = 0; j < 4; j++) { weightsw[i * 4 + j] /= tw; } } } Vector<Color> colors; if (vertex_colors.size() == points.size()) { colors.resize(len); PoolVector<Color>::Read color_r = vertex_colors.read(); for (int i = 0; i < len; i++) { colors.write[i] = color_r[i]; } } else { colors.push_back(color); } // Vector<int> indices = Geometry::triangulate_polygon(points); // VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); if (invert || polygons.size() == 0) { Vector<int> indices = Geometry::triangulate_polygon(points); VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } else { //draw individual polygons Vector<int> total_indices; for (int i = 0; i < polygons.size(); i++) { PoolVector<int> src_indices = polygons[i]; int ic = src_indices.size(); if (ic < 3) continue; PoolVector<int>::Read r = src_indices.read(); Vector<Vector2> tmp_points; tmp_points.resize(ic); for (int j = 0; j < ic; j++) { int idx = r[j]; ERR_CONTINUE(idx < 0 || idx >= points.size()); tmp_points.write[j] = points[r[j]]; } Vector<int> indices = Geometry::triangulate_polygon(tmp_points); int ic2 = indices.size(); const int *r2 = indices.ptr(); int bic = total_indices.size(); total_indices.resize(bic + ic2); int *w2 = total_indices.ptrw(); for (int j = 0; j < ic2; j++) { w2[j + bic] = r[r2[j]]; } } if (total_indices.size()) { VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), total_indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } #if 0 //use splits Vector<int> loop; int sc = splits.size(); PoolVector<int>::Read r = splits.read(); print_line("has splits, amount " + itos(splits.size())); Vector<Vector<int> > loops; // find a point that can be used to begin, must not be in a split, and have to the left and right the same one // like this one -> x---o // \ / \ . // o---o int base_point = -1; { int current_point = -1; int base_point_prev_split = -1; for (int i = 0; i < points.size(); i++) { //find if this point is in a split int split_index = -1; bool has_prev_split = false; int min_dist_to_end = 0x7FFFFFFF; for (int j = 0; j < sc; j += 2) { int split_pos = -1; int split_end = -1; if (r[j + 0] == i) { //found split in first point split_pos = r[j + 0]; split_end = r[j + 1]; } else if (r[j + 1] == i) { //found split in second point split_pos = r[j + 1]; split_end = r[j + 0]; } if (split_pos == split_end) { continue; //either nothing found or begin == end, this not a split in either case } if (j == base_point_prev_split) { has_prev_split = true; } //compute distance from split pos to split end in current traversal direction int dist_to_end = split_end > split_pos ? split_end - split_pos : (last - split_pos + split_end); if (dist_to_end < min_dist_to_end) { //always keep the valid split with the least distance to the loop min_dist_to_end = dist_to_end; split_index = j; } } if (split_index == -1) { current_point = i; //no split here, we are testing this point } else if (has_prev_split) { base_point = current_point; // there is a split and it contains the previous visited split, success break; } else { //invalidate current point and keep split current_point = -1; base_point_prev_split = split_index; } } } print_line("found base point: " + itos(base_point)); if (base_point != -1) { int point = base_point; int last = base_point; //go through all the points, find splits do { int split; int last_dist_to_end = -1; //maximum valid distance to end do { loop.push_back(point); //push current point split = -1; int end = -1; int max_dist_to_end = 0; //find if this point is in a split for (int j = 0; j < sc; j += 2) { int split_pos = -1; int split_end = -1; if (r[j + 0] == point) { //match first split index split_pos = r[j + 0]; split_end = r[j + 1]; } else if (r[j + 1] == point) { //match second split index split_pos = r[j + 1]; split_end = r[j + 0]; } if (split_pos == split_end) { continue; //either nothing found or begin == end, this not a split in either case } //compute distance from split pos to split end int dist_to_end = split_end > split_pos ? split_end - split_pos : (points.size() - split_pos + split_end); if (last_dist_to_end != -1 && dist_to_end >= last_dist_to_end) { //distance must be shorter than in last iteration, means we've tested this before so ignore continue; } else if (dist_to_end > max_dist_to_end) { //always keep the valid point with the most distance (as long as it's valid) max_dist_to_end = dist_to_end; split = split_pos; end = split_end; } } if (split != -1) { //found a split! int from = end; //add points until last is reached while (true) { //find if point is in a split loop.push_back(from); if (from == last) { break; } from++; if (from >= points.size()) { //wrap if reached end from = 0; } if (from == loop[0]) { break; //end because we reached split source } } loops.push_back(loop); //done with this loop loop.clear(); last_dist_to_end = max_dist_to_end; last = end; //algorithm can safely finish in this split point } } while (split != -1); } while (point != last); } if (loop.size() >=2 ) { //points remained //points remain loop.push_back(last); //no splits found, use last loops.push_back(loop); } print_line("total loops: " + itos(loops.size())); if (loops.size()) { //loops found Vector<int> indices; for (int i = 0; i < loops.size(); i++) { Vector<int> loop = loops[i]; Vector<Vector2> vertices; vertices.resize(loop.size()); for (int j = 0; j < vertices.size(); j++) { vertices.write[j] = points[loop[j]]; } Vector<int> sub_indices = Geometry::triangulate_polygon(vertices); int from = indices.size(); indices.resize(from + sub_indices.size()); for (int j = 0; j < sub_indices.size(); j++) { indices.write[from + j] = loop[sub_indices[j]]; } } VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID()); } #endif } } break; } }
void add_edge(T const &from, T const &to) { assert(has_node(from)); assert(has_node(to)); boost::add_edge(mapping_[from], mapping_[to], graph_); }
void ScrollBar::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { RID ci = get_canvas_item(); Ref<Texture> decr = highlight == HIGHLIGHT_DECR ? get_icon("decrement_highlight") : get_icon("decrement"); Ref<Texture> incr = highlight == HIGHLIGHT_INCR ? get_icon("increment_highlight") : get_icon("increment"); Ref<StyleBox> bg = has_focus() ? get_stylebox("scroll_focus") : get_stylebox("scroll"); Ref<StyleBox> grabber; if (drag.active) grabber = get_stylebox("grabber_pressed"); else if (highlight == HIGHLIGHT_RANGE) grabber = get_stylebox("grabber_highlight"); else grabber = get_stylebox("grabber"); Point2 ofs; VisualServer *vs = VisualServer::get_singleton(); vs->canvas_item_add_texture_rect(ci, Rect2(Point2(), decr->get_size()), decr->get_rid()); if (orientation == HORIZONTAL) ofs.x += decr->get_width(); else ofs.y += decr->get_height(); Size2 area = get_size(); if (orientation == HORIZONTAL) area.width -= incr->get_width() + decr->get_width(); else area.height -= incr->get_height() + decr->get_height(); bg->draw(ci, Rect2(ofs, area)); if (orientation == HORIZONTAL) ofs.width += area.width; else ofs.height += area.height; vs->canvas_item_add_texture_rect(ci, Rect2(ofs, decr->get_size()), incr->get_rid()); Rect2 grabber_rect; if (orientation == HORIZONTAL) { grabber_rect.size.width = get_grabber_size(); grabber_rect.size.height = get_size().height; grabber_rect.position.y = 0; grabber_rect.position.x = get_grabber_offset() + decr->get_width() + bg->get_margin(MARGIN_LEFT); } else { grabber_rect.size.width = get_size().width; grabber_rect.size.height = get_grabber_size(); grabber_rect.position.y = get_grabber_offset() + decr->get_height() + bg->get_margin(MARGIN_TOP); grabber_rect.position.x = 0; } grabber->draw(ci, grabber_rect); } if (p_what == NOTIFICATION_ENTER_TREE) { if (has_node(drag_slave_path)) { Node *n = get_node(drag_slave_path); drag_slave = n->cast_to<Control>(); } if (drag_slave) { drag_slave->connect("gui_input", this, "_drag_slave_input"); drag_slave->connect("tree_exited", this, "_drag_slave_exit", varray(), CONNECT_ONESHOT); } } if (p_what == NOTIFICATION_EXIT_TREE) { if (drag_slave) { drag_slave->disconnect("gui_input", this, "_drag_slave_input"); drag_slave->disconnect("tree_exited", this, "_drag_slave_exit"); } drag_slave = NULL; } if (p_what == NOTIFICATION_FIXED_PROCESS) { if (scrolling) { if (get_value() != target_scroll) { double target = target_scroll - get_value(); double dist = sqrt(target * target); double vel = ((target / dist) * 500) * get_fixed_process_delta_time(); if (vel >= dist) { set_value(target_scroll); } else { set_value(get_value() + vel); } } else { scrolling = false; set_fixed_process(false); } } else if (drag_slave_touching) { if (drag_slave_touching_deaccel) { Vector2 pos = Vector2(orientation == HORIZONTAL ? get_value() : 0, orientation == VERTICAL ? get_value() : 0); pos += drag_slave_speed * get_fixed_process_delta_time(); bool turnoff = false; if (orientation == HORIZONTAL) { if (pos.x < 0) { pos.x = 0; turnoff = true; } if (pos.x > (get_max() - get_page())) { pos.x = get_max() - get_page(); turnoff = true; } set_value(pos.x); float sgn_x = drag_slave_speed.x < 0 ? -1 : 1; float val_x = Math::abs(drag_slave_speed.x); val_x -= 1000 * get_fixed_process_delta_time(); if (val_x < 0) { turnoff = true; } drag_slave_speed.x = sgn_x * val_x; } else { if (pos.y < 0) { pos.y = 0; turnoff = true; } if (pos.y > (get_max() - get_page())) { pos.y = get_max() - get_page(); turnoff = true; } set_value(pos.y); float sgn_y = drag_slave_speed.y < 0 ? -1 : 1; float val_y = Math::abs(drag_slave_speed.y); val_y -= 1000 * get_fixed_process_delta_time(); if (val_y < 0) { turnoff = true; } drag_slave_speed.y = sgn_y * val_y; } if (turnoff) { set_fixed_process(false); drag_slave_touching = false; drag_slave_touching_deaccel = false; } } else { if (time_since_motion == 0 || time_since_motion > 0.1) { Vector2 diff = drag_slave_accum - last_drag_slave_accum; last_drag_slave_accum = drag_slave_accum; drag_slave_speed = diff / get_fixed_process_delta_time(); } time_since_motion += get_fixed_process_delta_time(); } } } if (p_what == NOTIFICATION_MOUSE_EXIT) { highlight = HIGHLIGHT_NONE; update(); } }