InputEvent InputEvent::xform_by(const Matrix32& p_xform) const { InputEvent ev=*this; switch(ev.type) { case InputEvent::MOUSE_BUTTON: { Vector2 g = p_xform.xform(Vector2(ev.mouse_button.global_x,ev.mouse_button.global_y)); Vector2 l = p_xform.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 = p_xform.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y)); Vector2 l = p_xform.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y)); Vector2 r = p_xform.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y)); Vector2 s = p_xform.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 = p_xform.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 = p_xform.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y)); Vector2 r = p_xform.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y)); Vector2 s = p_xform.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; }
void Polygon2DEditor::_uv_draw() { Ref<Texture> base_tex = node->get_texture(); if (base_tex.is_null()) return; Matrix32 mtx; mtx.elements[2]=-uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom,uv_draw_zoom)); VS::get_singleton()->canvas_item_set_clip(uv_edit_draw->get_canvas_item(),true); VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),mtx); uv_edit_draw->draw_texture(base_tex,Point2()); VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),Matrix32()); DVector<Vector2> uvs = node->get_uv(); Ref<Texture> handle = get_icon("EditorHandle","EditorIcons"); Rect2 rect(Point2(),mtx.basis_xform(base_tex->get_size())); rect.expand_to(mtx.basis_xform(uv_edit_draw->get_size())); for(int i=0;i<uvs.size();i++) { int next = (i+1)%uvs.size(); uv_edit_draw->draw_line(mtx.xform(uvs[i]),mtx.xform(uvs[next]),Color(0.9,0.5,0.5),2); uv_edit_draw->draw_texture(handle,mtx.xform(uvs[i])-handle->get_size()*0.5); rect.expand_to(mtx.basis_xform(uvs[i])); } rect=rect.grow(200); updating_uv_scroll=true; uv_hscroll->set_min(rect.pos.x); uv_hscroll->set_max(rect.pos.x+rect.size.x); uv_hscroll->set_page(uv_edit_draw->get_size().x); uv_hscroll->set_val(uv_draw_ofs.x); uv_hscroll->set_step(0.001); uv_vscroll->set_min(rect.pos.y); uv_vscroll->set_max(rect.pos.y+rect.size.y); uv_vscroll->set_page(uv_edit_draw->get_size().y); uv_vscroll->set_val(uv_draw_ofs.y); uv_vscroll->set_step(0.001); updating_uv_scroll=false; }
bool BodyPair2DSW::_test_ccd(float p_step,Body2DSW *p_A, int p_shape_A,const Matrix32& p_xform_A,Body2DSW *p_B, int p_shape_B,const Matrix32& p_xform_B,bool p_swap_result) { Vector2 motion = p_A->get_linear_velocity()*p_step; real_t mlen = motion.length(); if (mlen<CMP_EPSILON) return false; Vector2 mnormal = motion / mlen; real_t min,max; p_A->get_shape(p_shape_A)->project_rangev(mnormal,p_xform_A,min,max); bool fast_object = mlen > (max-min)*0.3; //going too fast in that direction if (!fast_object) { //did it move enough in this direction to even attempt raycast? let's say it should move more than 1/3 the size of the object in that axis return false; } //cast a segment from support in motion normal, in the same direction of motion by motion length //support is the worst case collision point, so real collision happened before int a; Vector2 s[2]; p_A->get_shape(p_shape_A)->get_supports(p_xform_A.basis_xform(mnormal).normalized(),s,a); Vector2 from = p_xform_A.xform(s[0]); Vector2 to = from + motion; Matrix32 from_inv = p_xform_B.affine_inverse(); Vector2 local_from = from_inv.xform(from-mnormal*mlen*0.1); //start from a little inside the bounding box Vector2 local_to = from_inv.xform(to); Vector2 rpos,rnorm; if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from,local_to,rpos,rnorm)) return false; //ray hit something Vector2 hitpos = p_xform_B.xform(rpos); Vector2 contact_A = to; Vector2 contact_B = hitpos; //create a contact if (p_swap_result) _contact_added_callback(contact_B,contact_A); else _contact_added_callback(contact_A,contact_B); return true; }
bool CollisionSolver2DSW::solve_static_line(const Shape2DSW *p_shape_A,const Matrix32& p_transform_A,const Shape2DSW *p_shape_B,const Matrix32& p_transform_B,CallbackResult p_result_callback,void *p_userdata,bool p_swap_result) { const LineShape2DSW *line = static_cast<const LineShape2DSW*>(p_shape_A); if (p_shape_B->get_type()==Physics2DServer::SHAPE_LINE) return false; Vector2 n = p_transform_A.basis_xform(line->get_normal()).normalized(); Vector2 p = p_transform_A.xform(line->get_normal()*line->get_d()); real_t d = n.dot(p); Vector2 supports[2]; int support_count; p_shape_B->get_supports(p_transform_A.affine_inverse().basis_xform(-n).normalized(),supports,support_count); bool found=false; for(int i=0;i<support_count;i++) { supports[i] = p_transform_B.xform( supports[i] ); real_t pd = n.dot(supports[i]); if (pd>=d) continue; found=true; Vector2 support_A = supports[i] - n*(pd-d); if (p_result_callback) { if (p_swap_result) p_result_callback(supports[i],support_A,p_userdata); else p_result_callback(support_A,supports[i],p_userdata); } } return found; }
void SpriteRegionEditor::_region_draw() { Ref<Texture> base_tex = node->get_texture(); if (base_tex.is_null()) return; Matrix32 mtx; mtx.elements[2]=-draw_ofs; mtx.scale_basis(Vector2(draw_zoom,draw_zoom)); VS::get_singleton()->canvas_item_set_clip(edit_draw->get_canvas_item(),true); VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(),mtx); edit_draw->draw_texture(base_tex,Point2()); VS::get_singleton()->canvas_item_add_set_transform(edit_draw->get_canvas_item(),Matrix32()); if (snap_show_grid) { Size2 s = edit_draw->get_size(); int last_cell; if (snap_step.x!=0) { for(int i=0;i<s.width;i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x)); if (i==0) last_cell=cell; if (last_cell!=cell) edit_draw->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3)); last_cell=cell; } } if (snap_step.y!=0) { for(int i=0;i<s.height;i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y)); if (i==0) last_cell=cell; if (last_cell!=cell) edit_draw->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3)); last_cell=cell; } } } Ref<Texture> select_handle = get_icon("EditorHandle","EditorIcons"); Rect2 scroll_rect(Point2(),mtx.basis_xform(base_tex->get_size())); scroll_rect.expand_to(mtx.basis_xform(edit_draw->get_size())); Vector2 endpoints[4]={ mtx.basis_xform(rect.pos), mtx.basis_xform(rect.pos+Vector2(rect.size.x,0)), mtx.basis_xform(rect.pos+rect.size), mtx.basis_xform(rect.pos+Vector2(0,rect.size.y)) }; for(int i=0;i<4;i++) { int prev = (i+3)%4; int next = (i+1)%4; Vector2 ofs = ((endpoints[i] - endpoints[prev]).normalized() + ((endpoints[i] - endpoints[next]).normalized())).normalized(); ofs*=1.4144*(select_handle->get_size().width/2); edit_draw->draw_line(endpoints[i]-draw_ofs, endpoints[next]-draw_ofs, Color(0.9,0.5,0.5), 2); edit_draw->draw_texture(select_handle,(endpoints[i]+ofs-(select_handle->get_size()/2)).floor()-draw_ofs); ofs = (endpoints[next]-endpoints[i])/2; ofs += (endpoints[next]-endpoints[i]).tangent().normalized()*(select_handle->get_size().width/2); edit_draw->draw_texture(select_handle,(endpoints[i]+ofs-(select_handle->get_size()/2)).floor()-draw_ofs); scroll_rect.expand_to(endpoints[i]); } scroll_rect=scroll_rect.grow(200); updating_scroll=true; hscroll->set_min(scroll_rect.pos.x); hscroll->set_max(scroll_rect.pos.x+scroll_rect.size.x); hscroll->set_page(edit_draw->get_size().x); hscroll->set_val(draw_ofs.x); hscroll->set_step(0.001); vscroll->set_min(scroll_rect.pos.y); vscroll->set_max(scroll_rect.pos.y+scroll_rect.size.y); vscroll->set_page(edit_draw->get_size().y); vscroll->set_val(draw_ofs.y); vscroll->set_step(0.001); updating_scroll=false; }
bool Path2DEditor::forward_input_event(const InputEvent& p_event) { if (!node) return false; if (!node->is_visible()) return false; if (!node->get_curve().is_valid()) return false; switch(p_event.type) { case InputEvent::MOUSE_BUTTON: { const InputEventMouseButton &mb=p_event.mouse_button; Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); Vector2 gpoint = Point2(mb.x,mb.y); Vector2 cpoint = !mb.mod.alt? snap_point(xform.affine_inverse().xform(gpoint)) : node->get_global_transform().affine_inverse().xform( snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) ); //first check if a point is to be added (segment split) real_t grab_treshold=EDITOR_DEF("poly_editor/point_grab_radius",8); // Test move point!! if ( mb.pressed && action==ACTION_NONE ) { Ref<Curve2D> curve = node->get_curve(); for(int i=0;i<curve->get_point_count();i++) { bool pointunder=false; { Point2 p = xform.xform( curve->get_point_pos(i) ); if (gpoint.distance_to(p) < grab_treshold ) { if (mb.button_index==BUTTON_LEFT && !mb.mod.shift && mode==MODE_EDIT) { action=ACTION_MOVING_POINT; action_point=i; moving_from=curve->get_point_pos(i); moving_screen_from=gpoint; return true; } else if ((mb.button_index==BUTTON_RIGHT && mode==MODE_EDIT) || (mb.button_index==BUTTON_LEFT && mode==MODE_DELETE)) { undo_redo->create_action("Remove Point from Curve"); undo_redo->add_do_method(curve.ptr(),"remove_point",i); undo_redo->add_undo_method(curve.ptr(),"add_point",curve->get_point_pos(i),curve->get_point_in(i),curve->get_point_out(i),i); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); return true; } else pointunder=true; } } if (mb.button_index==BUTTON_LEFT && i<(curve->get_point_count()-1)) { Point2 p = xform.xform( curve->get_point_pos(i)+curve->get_point_out(i) ); if (gpoint.distance_to(p) < grab_treshold && (mode == MODE_EDIT || mode==MODE_EDIT_CURVE) ) { action=ACTION_MOVING_OUT; action_point=i; moving_from=curve->get_point_out(i); moving_screen_from=gpoint; return true; } } if (mb.button_index==BUTTON_LEFT && i>0) { Point2 p = xform.xform( curve->get_point_pos(i)+curve->get_point_in(i) ); if (gpoint.distance_to(p) < grab_treshold && (mode == MODE_EDIT || mode==MODE_EDIT_CURVE)) { action=ACTION_MOVING_IN; action_point=i; moving_from=curve->get_point_in(i); moving_screen_from=gpoint; return true; } } if (pointunder) return true; } } // Test add point in empty space! if ( mb.pressed && mb.button_index==BUTTON_LEFT && ((mb.mod.command && mode == MODE_EDIT) || mode == MODE_CREATE)) { Ref<Curve2D> curve = node->get_curve(); undo_redo->create_action("Add Point to Curve"); undo_redo->add_do_method(curve.ptr(),"add_point",cpoint); undo_redo->add_undo_method(curve.ptr(),"remove_point",curve->get_point_count()); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); action=ACTION_MOVING_POINT; action_point=curve->get_point_count()-1; moving_from=curve->get_point_pos(action_point); moving_screen_from=gpoint; canvas_item_editor->get_viewport_control()->update(); return true; } if ( !mb.pressed && mb.button_index==BUTTON_LEFT && action!=ACTION_NONE) { Ref<Curve2D> curve = node->get_curve(); Vector2 new_pos = moving_from + xform.basis_xform( gpoint - moving_screen_from ); switch(action) { case ACTION_MOVING_POINT: { undo_redo->create_action("Move Point in Curve"); undo_redo->add_do_method(curve.ptr(),"set_point_pos",action_point,cpoint); undo_redo->add_undo_method(curve.ptr(),"set_point_pos",action_point,moving_from); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); } break; case ACTION_MOVING_IN: { undo_redo->create_action("Move In-Control in Curve"); undo_redo->add_do_method(curve.ptr(),"set_point_in",action_point,new_pos); undo_redo->add_undo_method(curve.ptr(),"set_point_in",action_point,moving_from); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); } break; case ACTION_MOVING_OUT: { undo_redo->create_action("Move Out-Control in Curve"); undo_redo->add_do_method(curve.ptr(),"set_point_out",action_point,new_pos); undo_redo->add_undo_method(curve.ptr(),"set_point_out",action_point,moving_from); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); } break; } action=ACTION_NONE; return true; } #if 0 switch(mode) { case MODE_CREATE: { if (mb.button_index==BUTTON_LEFT && mb.pressed) { if (!wip_active) { wip.clear(); wip.push_back( snap_point(cpoint) ); wip_active=true; edited_point_pos=snap_point(cpoint); canvas_item_editor->update(); edited_point=1; return true; } else { if (wip.size()>1 && xform.xform(wip[0]).distance_to(gpoint)<grab_treshold) { //wip closed _wip_close(); return true; } else { wip.push_back( snap_point(cpoint) ); edited_point=wip.size(); canvas_item_editor->update(); return true; //add wip point } } } else if (mb.button_index==BUTTON_RIGHT && mb.pressed && wip_active) { _wip_close(); } } break; case MODE_EDIT: { if (mb.button_index==BUTTON_LEFT) { if (mb.pressed) { if (mb.mod.control) { if (poly.size() < 3) { undo_redo->create_action("Edit Poly"); undo_redo->add_undo_method(node,"set_polygon",poly); poly.push_back(cpoint); undo_redo->add_do_method(node,"set_polygon",poly); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); return true; } //search edges int closest_idx=-1; Vector2 closest_pos; real_t closest_dist=1e10; for(int i=0;i<poly.size();i++) { Vector2 points[2] ={ xform.xform(poly[i]), xform.xform(poly[(i+1)%poly.size()]) }; Vector2 cp = Geometry::get_closest_point_to_segment_2d(gpoint,points); if (cp.distance_squared_to(points[0])<CMP_EPSILON2 || cp.distance_squared_to(points[1])<CMP_EPSILON2) continue; //not valid to reuse point real_t d = cp.distance_to(gpoint); if (d<closest_dist && d<grab_treshold) { closest_dist=d; closest_pos=cp; closest_idx=i; } } if (closest_idx>=0) { pre_move_edit=poly; poly.insert(closest_idx+1,snap_point(xform.affine_inverse().xform(closest_pos))); edited_point=closest_idx+1; edited_point_pos=snap_point(xform.affine_inverse().xform(closest_pos)); node->set_polygon(poly); canvas_item_editor->update(); return true; } } else { //look for points to move int closest_idx=-1; Vector2 closest_pos; real_t closest_dist=1e10; for(int i=0;i<poly.size();i++) { Vector2 cp =xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); if (d<closest_dist && d<grab_treshold) { closest_dist=d; closest_pos=cp; closest_idx=i; } } if (closest_idx>=0) { pre_move_edit=poly; edited_point=closest_idx; edited_point_pos=xform.affine_inverse().xform(closest_pos); canvas_item_editor->update(); return true; } } } else { if (edited_point!=-1) { //apply ERR_FAIL_INDEX_V(edited_point,poly.size(),false); poly[edited_point]=edited_point_pos; undo_redo->create_action("Edit Poly"); undo_redo->add_do_method(node,"set_polygon",poly); undo_redo->add_undo_method(node,"set_polygon",pre_move_edit); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); edited_point=-1; return true; } } } if (mb.button_index==BUTTON_RIGHT && mb.pressed && edited_point==-1) { int closest_idx=-1; Vector2 closest_pos; real_t closest_dist=1e10; for(int i=0;i<poly.size();i++) { Vector2 cp =xform.xform(poly[i]); real_t d = cp.distance_to(gpoint); if (d<closest_dist && d<grab_treshold) { closest_dist=d; closest_pos=cp; closest_idx=i; } } if (closest_idx>=0) { undo_redo->create_action("Edit Poly (Remove Point)"); undo_redo->add_undo_method(node,"set_polygon",poly); poly.remove(closest_idx); undo_redo->add_do_method(node,"set_polygon",poly); undo_redo->add_do_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(),"update"); undo_redo->commit_action(); return true; } } } break; } #endif } break; case InputEvent::MOUSE_MOTION: { const InputEventMouseMotion &mm=p_event.mouse_motion; if ( action!=ACTION_NONE) { Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); Vector2 gpoint = Point2(mm.x,mm.y); Vector2 cpoint = !mm.mod.alt? snap_point(xform.affine_inverse().xform(gpoint)) : node->get_global_transform().affine_inverse().xform( snap_point(canvas_item_editor->get_canvas_transform().affine_inverse().xform(gpoint)) ); Ref<Curve2D> curve = node->get_curve(); Vector2 new_pos = moving_from + xform.basis_xform( gpoint - moving_screen_from ); switch(action) { case ACTION_MOVING_POINT: { curve->set_point_pos(action_point,cpoint); } break; case ACTION_MOVING_IN: { curve->set_point_in(action_point,new_pos); } break; case ACTION_MOVING_OUT: { curve->set_point_out(action_point,new_pos); } break; } canvas_item_editor->get_viewport_control()->update(); return true; } #if 0 if (edited_point!=-1 && (wip_active || mm.button_mask&BUTTON_MASK_LEFT)) { Matrix32 xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); Vector2 gpoint = Point2(mm.x,mm.y); edited_point_pos = snap_point(xform.affine_inverse().xform(gpoint)); canvas_item_editor->update(); } #endif } break; } return false; }
void Polygon2DEditor::_uv_draw() { Ref<Texture> base_tex = node->get_texture(); if (base_tex.is_null()) return; Matrix32 mtx; mtx.elements[2]=-uv_draw_ofs; mtx.scale_basis(Vector2(uv_draw_zoom,uv_draw_zoom)); VS::get_singleton()->canvas_item_set_clip(uv_edit_draw->get_canvas_item(),true); VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),mtx); uv_edit_draw->draw_texture(base_tex,Point2()); VS::get_singleton()->canvas_item_add_set_transform(uv_edit_draw->get_canvas_item(),Matrix32()); if (snap_show_grid) { Size2 s = uv_edit_draw->get_size(); int last_cell; if (snap_step.x!=0) { for(int i=0;i<s.width;i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(i,0)).x-snap_offset.x)/snap_step.x)); if (i==0) last_cell=cell; if (last_cell!=cell) uv_edit_draw->draw_line(Point2(i,0),Point2(i,s.height),Color(0.3,0.7,1,0.3)); last_cell=cell; } } if (snap_step.y!=0) { for(int i=0;i<s.height;i++) { int cell = Math::fast_ftoi(Math::floor((mtx.affine_inverse().xform(Vector2(0,i)).y-snap_offset.y)/snap_step.y)); if (i==0) last_cell=cell; if (last_cell!=cell) uv_edit_draw->draw_line(Point2(0,i),Point2(s.width,i),Color(0.3,0.7,1,0.3)); last_cell=cell; } } } DVector<Vector2> uvs = node->get_uv(); Ref<Texture> handle = get_icon("EditorHandle","EditorIcons"); Rect2 rect(Point2(),mtx.basis_xform(base_tex->get_size())); rect.expand_to(mtx.basis_xform(uv_edit_draw->get_size())); for(int i=0;i<uvs.size();i++) { int next = (i+1)%uvs.size(); uv_edit_draw->draw_line(mtx.xform(uvs[i]),mtx.xform(uvs[next]),Color(0.9,0.5,0.5),2); uv_edit_draw->draw_texture(handle,mtx.xform(uvs[i])-handle->get_size()*0.5); rect.expand_to(mtx.basis_xform(uvs[i])); } rect=rect.grow(200); updating_uv_scroll=true; uv_hscroll->set_min(rect.pos.x); uv_hscroll->set_max(rect.pos.x+rect.size.x); uv_hscroll->set_page(uv_edit_draw->get_size().x); uv_hscroll->set_val(uv_draw_ofs.x); uv_hscroll->set_step(0.001); uv_vscroll->set_min(rect.pos.y); uv_vscroll->set_max(rect.pos.y+rect.size.y); uv_vscroll->set_page(uv_edit_draw->get_size().y); uv_vscroll->set_val(uv_draw_ofs.y); uv_vscroll->set_step(0.001); updating_uv_scroll=false; }
void Particles2D::_process_particles(float p_delta) { if (particles.size()==0 || lifetime==0) return; p_delta*=time_scale; float frame_time=p_delta; if (emit_timeout > 0) { time_to_live -= frame_time; if (time_to_live < 0) { emitting = false; _change_notify("config/emitting"); }; }; float next_time = time+frame_time; if (next_time > lifetime) next_time=Math::fmod(next_time,lifetime); Particle *pdata=&particles[0]; int particle_count=particles.size(); Matrix32 xform; if (!local_space) xform=get_global_transform(); active_count=0; DVector<Point2>::Read r; int emission_point_count=0; if (emission_points.size()) { emission_point_count=emission_points.size(); r=emission_points.read(); } int attractor_count=0; AttractorCache *attractor_ptr=NULL; if (attractors.size()) { if (attractors.size()!=attractor_cache.size()) { attractor_cache.resize(attractors.size()); } int idx=0; Matrix32 m; if (local_space) { m= get_global_transform().affine_inverse(); } for (Set<ParticleAttractor2D*>::Element *E=attractors.front();E;E=E->next()) { attractor_cache[idx].pos=m.xform( E->get()->get_global_pos() ); attractor_cache[idx].attractor=E->get(); idx++; } attractor_ptr=attractor_cache.ptr(); attractor_count=attractor_cache.size(); } for(int i=0;i<particle_count;i++) { Particle &p=pdata[i]; float restart_time = (i * lifetime / particle_count) * explosiveness; bool restart=false; if ( next_time < time ) { if (restart_time > time || restart_time < next_time ) restart=true; } else if (restart_time > time && restart_time < next_time ) { restart=true; } if (restart) { if (emitting) { p.pos=emissor_offset; if (emission_point_count) { Vector2 ep = r[Math::rand()%emission_point_count]; if (!local_space) { p.pos=xform.xform(p.pos+ep*extents); } else { p.pos+=ep*extents; } } else { if (!local_space) { p.pos=xform.xform(p.pos+Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y))); } else { p.pos+=Vector2(Math::random(-extents.x,extents.x),Math::random(-extents.y,extents.y)); } } p.seed=Math::rand() % 12345678; uint32_t rand_seed=p.seed*(i+1); float angle = Math::deg2rad(param[PARAM_DIRECTION]+_rand_from_seed(&rand_seed)*param[PARAM_SPREAD]); p.velocity=Vector2( Math::sin(angle), Math::cos(angle) ); if (!local_space) { p.velocity = xform.basis_xform(p.velocity).normalized(); } p.velocity*=param[PARAM_LINEAR_VELOCITY]+param[PARAM_LINEAR_VELOCITY]*_rand_from_seed(&rand_seed)*randomness[PARAM_LINEAR_VELOCITY]; p.velocity+=initial_velocity; p.active=true; p.rot=Math::deg2rad(param[PARAM_INITIAL_ANGLE]+param[PARAM_INITIAL_ANGLE]*randomness[PARAM_INITIAL_ANGLE]*_rand_from_seed(&rand_seed)); active_count++; p.frame=Math::fmod(param[PARAM_ANIM_INITIAL_POS]+randomness[PARAM_ANIM_INITIAL_POS]*_rand_from_seed(&rand_seed),1.0); } else { p.active=false; } } else { if (!p.active) continue; uint32_t rand_seed=p.seed*(i+1); Vector2 force; //apply gravity float gravity_dir = Math::deg2rad( param[PARAM_GRAVITY_DIRECTION]+180*randomness[PARAM_GRAVITY_DIRECTION]*_rand_from_seed(&rand_seed)); force+=Vector2( Math::sin(gravity_dir), Math::cos(gravity_dir) ) * (param[PARAM_GRAVITY_STRENGTH]+param[PARAM_GRAVITY_STRENGTH]*randomness[PARAM_GRAVITY_STRENGTH]*_rand_from_seed(&rand_seed)); //apply radial Vector2 rvec = (p.pos - emissor_offset).normalized(); force+=rvec*(param[PARAM_RADIAL_ACCEL]+param[PARAM_RADIAL_ACCEL]*randomness[PARAM_RADIAL_ACCEL]*_rand_from_seed(&rand_seed)); //apply orbit float orbitvel = (param[PARAM_ORBIT_VELOCITY]+param[PARAM_ORBIT_VELOCITY]*randomness[PARAM_ORBIT_VELOCITY]*_rand_from_seed(&rand_seed)); if (orbitvel!=0) { Vector2 rel = p.pos - xform.elements[2]; Matrix32 rot(orbitvel*frame_time,Vector2()); p.pos = rot.xform(rel) + xform.elements[2]; } Vector2 tvec=rvec.tangent(); force+=tvec*(param[PARAM_TANGENTIAL_ACCEL]+param[PARAM_TANGENTIAL_ACCEL]*randomness[PARAM_TANGENTIAL_ACCEL]*_rand_from_seed(&rand_seed)); for(int j=0;j<attractor_count;j++) { Vector2 vec = (attractor_ptr[j].pos - p.pos); float vl = vec.length(); if (!attractor_ptr[j].attractor->enabled || vl==0 || vl > attractor_ptr[j].attractor->radius) continue; force+=vec*attractor_ptr[j].attractor->gravity; float fvl = p.velocity.length(); if (fvl && attractor_ptr[j].attractor->absorption) { Vector2 target = vec.normalized(); p.velocity = p.velocity.normalized().linear_interpolate(target,MIN(frame_time*attractor_ptr[j].attractor->absorption,1))*fvl; } if (attractor_ptr[j].attractor->disable_radius && vl < attractor_ptr[j].attractor->disable_radius) { p.active=false; } } p.velocity+=force*frame_time; if (param[PARAM_DAMPING]) { float dmp = param[PARAM_DAMPING]+param[PARAM_DAMPING]*randomness[PARAM_DAMPING]*_rand_from_seed(&rand_seed); float v = p.velocity.length(); v -= dmp * frame_time; if (v<=0) { p.velocity=Vector2(); } else { p.velocity=p.velocity.normalized() * v; } } p.pos+=p.velocity*frame_time; p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time; float anim_spd=param[PARAM_ANIM_SPEED_SCALE]+param[PARAM_ANIM_SPEED_SCALE]*randomness[PARAM_ANIM_SPEED_SCALE]*_rand_from_seed(&rand_seed); p.frame=Math::fposmod(p.frame+(frame_time/lifetime)*anim_spd,1.0); active_count++; } } time=Math::fmod( time+frame_time, lifetime ); if (!emitting && active_count==0) { set_process(false); } update(); }