diff options
Diffstat (limited to 'scene')
88 files changed, 2591 insertions, 579 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 0b00ac9560..342b86b4c1 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -28,6 +28,8 @@ /*************************************************************************/ #include "animated_sprite.h" #include "scene/scene_string_names.h" +#include "os/os.h" + void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) { set_offset(p_pivot); @@ -153,6 +155,9 @@ void AnimatedSprite::_notification(int p_what) { if (centered) ofs-=s/2; + if (OS::get_singleton()->get_use_pixel_snap()) { + ofs=ofs.floor(); + } Rect2 dst_rect(ofs,s); if (hflip) diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 92d5088b81..357aaa225b 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -265,7 +265,7 @@ void CanvasItem::_propagate_visibility_changed(bool p_visible) { CanvasItem *c=get_child(i)->cast_to<CanvasItem>(); - if (c && c->hidden!=p_visible) //should the toplevels stop propagation? i think so but.. + if (c && !c->hidden) //should the toplevels stop propagation? i think so but.. c->_propagate_visibility_changed(p_visible); } @@ -1172,6 +1172,14 @@ Matrix32 CanvasItem::get_viewport_transform() const { } +void CanvasItem::set_notify_local_transform(bool p_enable) { + notify_local_transform=p_enable; +} + +bool CanvasItem::is_local_transform_notification_enabled() const { + return notify_local_transform; +} + CanvasItem::CanvasItem() : xform_change(this) { @@ -1191,6 +1199,7 @@ CanvasItem::CanvasItem() : xform_change(this) { canvas_layer=NULL; use_parent_material=false; global_invalid=true; + notify_local_transform=false; light_mask=1; C=NULL; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 6d8308dbe4..4885256c64 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -126,6 +126,7 @@ private: bool block_transform_notify; bool behind; bool use_parent_material; + bool notify_local_transform; Ref<CanvasItemMaterial> material; @@ -155,7 +156,7 @@ private: protected: - _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } + _FORCE_INLINE_ void _notify_transform() { if (!is_inside_tree()) return; _notify_transform(this); if (!block_transform_notify && notify_local_transform) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } void item_rect_changed(); @@ -263,6 +264,10 @@ public: Vector2 get_global_mouse_pos() const; Vector2 get_local_mouse_pos() const; + void set_notify_local_transform(bool p_enable); + bool is_local_transform_notification_enabled() const; + + CanvasItem(); ~CanvasItem(); }; diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index ceea41d1c8..1479cb7881 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -33,7 +33,7 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { - if (unparenting) + if (unparenting || !can_update_body) return; CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); @@ -49,6 +49,7 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon); + shape_from=co->get_shape_count(); for(int i=0;i<decomp.size();i++) { Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D ); convex->set_points(decomp[i]); @@ -57,6 +58,11 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { co->set_shape_as_trigger(co->get_shape_count()-1,true); } + shape_to=co->get_shape_count()-1; + if (shape_to<shape_from) { + shape_from=-1; + shape_to=-1; + } } else { @@ -78,6 +84,9 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { if (trigger) co->set_shape_as_trigger(co->get_shape_count()-1,true); + shape_from=co->get_shape_count()-1; + shape_to=co->get_shape_count()-1; + } @@ -86,6 +95,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { void CollisionPolygon2D::_update_parent() { + if (!can_update_body) + return; Node *parent = get_parent(); if (!parent) return; @@ -101,33 +112,55 @@ void CollisionPolygon2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_ENTER_TREE: { unparenting=false; + can_update_body=get_tree()->is_editor_hint(); + } break; + case NOTIFICATION_EXIT_TREE: { + can_update_body=false; } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (!is_inside_tree()) break; - _update_parent(); + if (can_update_body) { + _update_parent(); + } else if (shape_from>=0 && shape_to>=0) { + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + for(int i=shape_from;i<=shape_to;i++) { + co->set_shape_transform(i,get_transform()); + } + } + } break; case NOTIFICATION_DRAW: { + + if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { + break; + } + + for(int i=0;i<polygon.size();i++) { Vector2 p = polygon[i]; Vector2 n = polygon[(i+1)%polygon.size()]; - draw_line(p,n,Color(0,0.6,0.7,0.5),3); + draw_line(p,n,Color(0.9,0.2,0.0,0.8),3); } +//#define DEBUG_DECOMPOSE +#if defined(TOOLS_ENABLED) && defined (DEBUG_DECOMPOSE) Vector< Vector<Vector2> > decomp = Geometry::decompose_polygon(polygon); -#define DEBUG_DECOMPOSE -#ifdef DEBUG_DECOMPOSE Color c(0.4,0.9,0.1); for(int i=0;i<decomp.size();i++) { c.set_hsv( Math::fmod(c.get_h() + 0.738,1),c.get_s(),c.get_v(),0.5); draw_colored_polygon(decomp[i],c); } +#else + draw_colored_polygon(polygon,get_tree()->get_debug_collisions_color()); #endif + + } break; case NOTIFICATION_UNPARENTED: { unparenting = true; @@ -141,20 +174,22 @@ void CollisionPolygon2D::set_polygon(const Vector<Point2>& p_polygon) { polygon=p_polygon; - for(int i=0;i<polygon.size();i++) { - if (i==0) - aabb=Rect2(polygon[i],Size2()); - else - aabb.expand_to(polygon[i]); - } - if (aabb==Rect2()) { + if (can_update_body) { + for(int i=0;i<polygon.size();i++) { + if (i==0) + aabb=Rect2(polygon[i],Size2()); + else + aabb.expand_to(polygon[i]); + } + if (aabb==Rect2()) { - aabb=Rect2(-10,-10,20,20); - } else { - aabb.pos-=aabb.size*0.3; - aabb.size+=aabb.size*0.6; + aabb=Rect2(-10,-10,20,20); + } else { + aabb.pos-=aabb.size*0.3; + aabb.size+=aabb.size*0.6; + } + _update_parent(); } - _update_parent(); update(); } @@ -184,6 +219,13 @@ void CollisionPolygon2D::set_trigger(bool p_trigger) { trigger=p_trigger; _update_parent(); + if (!can_update_body && is_inside_tree() && shape_from>=0 && shape_to>=0) { + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + for(int i=shape_from;i<=shape_to;i++) { + co->set_shape_as_trigger(i,p_trigger); + } + + } } bool CollisionPolygon2D::is_trigger() const{ @@ -192,6 +234,17 @@ bool CollisionPolygon2D::is_trigger() const{ } +void CollisionPolygon2D::_set_shape_range(const Vector2& p_range) { + + shape_from=p_range.x; + shape_to=p_range.y; +} + +Vector2 CollisionPolygon2D::_get_shape_range() const { + + return Vector2(shape_from,shape_to); +} + void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object); @@ -204,9 +257,17 @@ void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_trigger"),&CollisionPolygon2D::set_trigger); ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionPolygon2D::is_trigger); + ObjectTypeDB::bind_method(_MD("_set_shape_range","shape_range"),&CollisionPolygon2D::_set_shape_range); + ObjectTypeDB::bind_method(_MD("_get_shape_range"),&CollisionPolygon2D::_get_shape_range); + + ObjectTypeDB::bind_method(_MD("get_collision_object_first_shape"),&CollisionPolygon2D::get_collision_object_first_shape); + ObjectTypeDB::bind_method(_MD("get_collision_object_last_shape"),&CollisionPolygon2D::get_collision_object_last_shape); + ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Segments"),_SCS("set_build_mode"),_SCS("get_build_mode")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"shape_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_shape_range"),_SCS("_get_shape_range")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + } CollisionPolygon2D::CollisionPolygon2D() { @@ -215,6 +276,9 @@ CollisionPolygon2D::CollisionPolygon2D() { build_mode=BUILD_SOLIDS; trigger=false; unparenting=false; - + shape_from=-1; + shape_to=-1; + can_update_body=false; + set_notify_local_transform(true); } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 4e78868082..4bc9713c8a 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -56,6 +56,14 @@ protected: void _add_to_collision_object(Object *p_obj); void _update_parent(); + bool can_update_body; + int shape_from; + int shape_to; + + void _set_shape_range(const Vector2& p_range); + Vector2 _get_shape_range() const; + + protected: void _notification(int p_what); @@ -72,6 +80,10 @@ public: Vector<Point2> get_polygon() const; virtual Rect2 get_item_rect() const; + + int get_collision_object_first_shape() const { return shape_from; } + int get_collision_object_last_shape() const { return shape_to; } + CollisionPolygon2D(); }; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 5012c54b17..85751fc735 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -44,10 +44,12 @@ void CollisionShape2D::_add_to_collision_object(Object *p_obj) { CollisionObject2D *co = p_obj->cast_to<CollisionObject2D>(); ERR_FAIL_COND(!co); + update_shape_index=co->get_shape_count(); co->add_shape(shape,get_transform()); if (trigger) co->set_shape_as_trigger(co->get_shape_count()-1,true); + } void CollisionShape2D::_shape_changed() { @@ -74,12 +76,27 @@ void CollisionShape2D::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { unparenting=false; + can_update_body=get_tree()->is_editor_hint(); + } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { if (!is_inside_tree()) break; - _update_parent(); + if (can_update_body) { + _update_parent(); + } else if (update_shape_index>=0){ + + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + if (co) { + co->set_shape_transform(update_shape_index,get_transform()); + } + + } + + } break; + case NOTIFICATION_EXIT_TREE: { + can_update_body=false; } break; /* @@ -92,106 +109,22 @@ void CollisionShape2D::_notification(int p_what) { } break;*/ case NOTIFICATION_DRAW: { - rect=Rect2(); - - Color draw_col=Color(0,0.6,0.7,0.5); - - if (shape->cast_to<LineShape2D>()) { - - LineShape2D *l = shape->cast_to<LineShape2D>(); - Vector2 point = l->get_d() * l->get_normal(); - - Vector2 l1[2]={point-l->get_normal().tangent()*100,point+l->get_normal().tangent()*100}; - draw_line(l1[0],l1[1],draw_col,3); - Vector2 l2[2]={point,point+l->get_normal()*30}; - draw_line(l2[0],l2[1],draw_col,3); - rect.pos=l1[0]; - rect.expand_to(l1[1]); - rect.expand_to(l2[0]); - rect.expand_to(l2[1]); - - } else if (shape->cast_to<SegmentShape2D>()) { - - SegmentShape2D *s = shape->cast_to<SegmentShape2D>(); - draw_line(s->get_a(),s->get_b(),draw_col,3); - rect.pos=s->get_a(); - rect.expand_to(s->get_b()); - - } else if (shape->cast_to<RayShape2D>()) { - - RayShape2D *s = shape->cast_to<RayShape2D>(); - - Vector2 tip = Vector2(0,s->get_length()); - draw_line(Vector2(),tip,draw_col,3); - Vector<Vector2> pts; - float tsize=4; - pts.push_back(tip+Vector2(0,tsize)); - pts.push_back(tip+Vector2(0.707*tsize,0)); - pts.push_back(tip+Vector2(-0.707*tsize,0)); - Vector<Color> cols; - for(int i=0;i<3;i++) - cols.push_back(draw_col); - - draw_primitive(pts,cols,Vector<Vector2>()); //small arrow - - rect.pos=Vector2(); - rect.expand_to(tip); - rect=rect.grow(0.707*tsize); - - } else if (shape->cast_to<CircleShape2D>()) { - - CircleShape2D *s = shape->cast_to<CircleShape2D>(); - Vector<Vector2> points; - for(int i=0;i<24;i++) { - - points.push_back(Vector2(Math::cos(i*Math_PI*2/24.0),Math::sin(i*Math_PI*2/24.0))*s->get_radius()); - } - - draw_colored_polygon(points,draw_col); - rect.pos=-Point2(s->get_radius(),s->get_radius()); - rect.size=Point2(s->get_radius(),s->get_radius())*2.0; - - } else if (shape->cast_to<RectangleShape2D>()) { - - RectangleShape2D *s = shape->cast_to<RectangleShape2D>(); - Vector2 he = s->get_extents(); - rect=Rect2(-he,he*2.0); - draw_rect(rect,draw_col);; - - } else if (shape->cast_to<CapsuleShape2D>()) { - - CapsuleShape2D *s = shape->cast_to<CapsuleShape2D>(); - - Vector<Vector2> points; - for(int i=0;i<24;i++) { - Vector2 ofs = Vector2(0,(i>6 && i<=18) ? -s->get_height()*0.5 : s->get_height()*0.5); - - points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() + ofs); - if (i==6 || i==18) - points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*s->get_radius() - ofs); - } - - draw_colored_polygon(points,draw_col); - Vector2 he=Point2(s->get_radius(),s->get_radius()+s->get_height()*0.5); - rect.pos=-he; - rect.size=he*2.0; + if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_hint()) { + break; + } - } else if (shape->cast_to<ConvexPolygonShape2D>()) { + if (!shape.is_valid()) { + break; + } - ConvexPolygonShape2D *s = shape->cast_to<ConvexPolygonShape2D>(); + rect=Rect2(); - Vector<Vector2> points = s->get_points(); - for(int i=0;i<points.size();i++) { - if (i==0) - rect.pos=points[i]; - else - rect.expand_to(points[i]); - } - draw_colored_polygon(points,draw_col); + Color draw_col=get_tree()->get_debug_collisions_color(); + shape->draw(get_canvas_item(),draw_col); - } + rect=shape->get_rect(); rect=rect.grow(3); } break; @@ -209,7 +142,14 @@ void CollisionShape2D::set_shape(const Ref<Shape2D>& p_shape) { shape->disconnect("changed",this,"_shape_changed"); shape=p_shape; update(); - _update_parent(); + if (is_inside_tree() && can_update_body) + _update_parent(); + if (is_inside_tree() && !can_update_body && update_shape_index>=0) { + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + if (co) { + co->set_shape(update_shape_index,p_shape); + } + } if (shape.is_valid()) shape->connect("changed",this,"_shape_changed"); @@ -228,7 +168,14 @@ Rect2 CollisionShape2D::get_item_rect() const { void CollisionShape2D::set_trigger(bool p_trigger) { trigger=p_trigger; - _update_parent(); + if (can_update_body) { + _update_parent(); + } else if (is_inside_tree() && update_shape_index>=0){ + CollisionObject2D *co = get_parent()->cast_to<CollisionObject2D>(); + if (co) { + co->set_shape_as_trigger(update_shape_index,p_trigger); + } + } } bool CollisionShape2D::is_trigger() const{ @@ -236,6 +183,19 @@ bool CollisionShape2D::is_trigger() const{ return trigger; } + +void CollisionShape2D::_set_update_shape_index(int p_index) { + + + update_shape_index=p_index; +} + +int CollisionShape2D::_get_update_shape_index() const{ + + return update_shape_index; +} + + void CollisionShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_shape","shape"),&CollisionShape2D::set_shape); @@ -245,14 +205,23 @@ void CollisionShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_trigger","enable"),&CollisionShape2D::set_trigger); ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape2D::is_trigger); + ObjectTypeDB::bind_method(_MD("_set_update_shape_index","index"),&CollisionShape2D::_set_update_shape_index); + ObjectTypeDB::bind_method(_MD("_get_update_shape_index"),&CollisionShape2D::_get_update_shape_index); + + ObjectTypeDB::bind_method(_MD("get_collision_object_shape_index"),&CollisionShape2D::get_collision_object_shape_index); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D"),_SCS("set_shape"),_SCS("get_shape")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_NOEDITOR), _SCS("_set_update_shape_index"), _SCS("_get_update_shape_index")); + } CollisionShape2D::CollisionShape2D() { rect=Rect2(-Point2(10,10),Point2(20,20)); - + set_notify_local_transform(true); trigger=false; unparenting = false; + can_update_body = false; + update_shape_index=-1; } diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h index 507912d31e..82e1137174 100644 --- a/scene/2d/collision_shape_2d.h +++ b/scene/2d/collision_shape_2d.h @@ -39,7 +39,13 @@ class CollisionShape2D : public Node2D { Rect2 rect; bool trigger; bool unparenting; + bool can_update_body; void _shape_changed(); + int update_shape_index; + + void _set_update_shape_index(int p_index); + int _get_update_shape_index() const; + protected: void _update_parent(); @@ -55,6 +61,8 @@ public: void set_trigger(bool p_trigger); bool is_trigger() const; + int get_collision_object_shape_index() const { return _get_update_shape_index(); } + CollisionShape2D(); }; diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp index 5db0e0a9fc..b7d51730a0 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation2d.cpp @@ -8,8 +8,6 @@ void Navigation2D::_navpoly_link(int p_id) { NavMesh &nm=navpoly_map[p_id]; ERR_FAIL_COND(nm.linked); - print_line("LINK"); - DVector<Vector2> vertices=nm.navpoly->get_vertices(); int len = vertices.size(); if (len==0) @@ -48,7 +46,6 @@ void Navigation2D::_navpoly_link(int p_id) { e.point=_get_point(ep); p.edges[j]=e; - int idxn = indices[(j+1)%plen]; if (idxn<0 || idxn>=len) { valid=false; @@ -121,7 +118,7 @@ void Navigation2D::_navpoly_unlink(int p_id) { NavMesh &nm=navpoly_map[p_id]; ERR_FAIL_COND(!nm.linked); - print_line("UNLINK"); + //print_line("UNLINK"); for (List<Polygon>::Element *E=nm.polygons.front();E;E=E->next()) { @@ -358,7 +355,6 @@ Vector<Vector2> Navigation2D::get_simple_path(const Vector2& p_start, const Vect if (!begin_poly || !end_poly) { - //print_line("No Path Path"); return Vector<Vector2>(); //no path } diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp index fc69ea8a0d..792f079ab0 100644 --- a/scene/2d/navigation_polygon.cpp +++ b/scene/2d/navigation_polygon.cpp @@ -279,7 +279,7 @@ void NavigationPolygonInstance::set_enabled(bool p_enabled) { } - if (get_tree()->is_editor_hint()) + if (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) update(); // update_gizmo(); @@ -338,7 +338,7 @@ void NavigationPolygonInstance::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - if (is_inside_tree() && get_tree()->is_editor_hint() && navpoly.is_valid()) { + if (is_inside_tree() && (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint()) && navpoly.is_valid()) { DVector<Vector2> verts=navpoly->get_vertices(); int vsize = verts.size(); @@ -348,9 +348,9 @@ void NavigationPolygonInstance::_notification(int p_what) { Color color; if (enabled) { - color=Color(0.1,0.8,1.0,0.4); + color=get_tree()->get_debug_navigation_color(); } else { - color=Color(1.0,0.8,0.1,0.4); + color=get_tree()->get_debug_navigation_disabled_color(); } Vector<Color> colors; Vector<Vector2> vertices; @@ -423,7 +423,7 @@ Ref<NavigationPolygon> NavigationPolygonInstance::get_navigation_polygon() const void NavigationPolygonInstance::_navpoly_changed() { - if (is_inside_tree() && get_tree()->is_editor_hint()) + if (is_inside_tree() && (get_tree()->is_editor_hint() || get_tree()->is_debugging_navigation_hint())) update(); } diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 20abe42cd9..05594fd79c 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -115,17 +115,17 @@ void RayCast2D::_notification(int p_what) { set_fixed_process(false); } break; -#ifdef TOOLS_ENABLED + case NOTIFICATION_DRAW: { - if (!get_tree()->is_editor_hint()) + if (!get_tree()->is_editor_hint() && !get_tree()->is_debugging_collisions_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); + Color dcol=get_tree()->get_debug_collisions_color();//0.9,0.2,0.2,0.4); draw_line(Vector2(),cast_to,dcol,3); Vector<Vector2> pts; float tsize=4; @@ -139,7 +139,7 @@ void RayCast2D::_notification(int p_what) { draw_primitive(pts,cols,Vector<Vector2>()); //small arrow } break; -#endif + case NOTIFICATION_FIXED_PROCESS: { diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp index bb37475944..ec17ffc55e 100644 --- a/scene/2d/sample_player_2d.cpp +++ b/scene/2d/sample_player_2d.cpp @@ -214,7 +214,7 @@ void SamplePlayer2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SamplePlayer2D::set_sample_library); ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SamplePlayer2D::get_sample_library); - ObjectTypeDB::bind_method(_MD("set_polyphony","voices"),&SamplePlayer2D::set_polyphony); + ObjectTypeDB::bind_method(_MD("set_polyphony","max_voices"),&SamplePlayer2D::set_polyphony); ObjectTypeDB::bind_method(_MD("get_polyphony"),&SamplePlayer2D::get_polyphony); ObjectTypeDB::bind_method(_MD("play","sample","voice"),&SamplePlayer2D::play,DEFVAL(NEXT_VOICE)); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 6705cebf37..89d9966958 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -30,6 +30,7 @@ #include "core/core_string_names.h" #include "scene/scene_string_names.h" #include "scene/main/viewport.h" +#include "os/os.h" void Sprite::edit_set_pivot(const Point2& p_pivot) { @@ -85,6 +86,9 @@ void Sprite::_notification(int p_what) { Point2 ofs=offset; if (centered) ofs-=s/2; + if (OS::get_singleton()->get_use_pixel_snap()) { + ofs=ofs.floor(); + } Rect2 dst_rect(ofs,s); @@ -189,6 +193,7 @@ void Sprite::set_region_rect(const Rect2& p_region_rect) { if (region && changed) { update(); item_rect_changed(); + _change_notify("region_rect"); } } @@ -421,6 +426,9 @@ void ViewportSprite::_notification(int p_what) { if (centered) ofs-=s/2; + if (OS::get_singleton()->get_use_pixel_snap()) { + ofs=ofs.floor(); + } Rect2 dst_rect(ofs,s); texture->draw_rect_region(ci,dst_rect,src_rect,modulate); diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 17f93f816f..418ee192b2 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -30,6 +30,7 @@ #include "io/marshalls.h" #include "servers/physics_2d_server.h" #include "method_bind_ext.inc" +#include "os/os.h" int TileMap::_get_quadrant_size() const { @@ -262,6 +263,14 @@ void TileMap::_update_dirty_quadrants() { Vector2 qofs; + SceneTree *st=SceneTree::get_singleton(); + Color debug_collision_color; + + bool debug_shapes = st && st->is_debugging_collisions_hint(); + if (debug_shapes) { + debug_collision_color=st->get_debug_collisions_color(); + } + while (dirty_quadrant_list.first()) { Quadrant &q = *dirty_quadrant_list.first()->self(); @@ -398,11 +407,19 @@ void TileMap::_update_dirty_quadrants() { _fix_cell_transform(xform,c,shape_ofs+center_ofs,s); - ps->body_add_shape(q.body,shape->get_rid(),xform); + if (debug_shapes) { + vs->canvas_item_add_set_transform(canvas_item,xform); + shape->draw(canvas_item,debug_collision_color); + + } + ps->body_add_shape(q.body,shape->get_rid(),xform); ps->body_set_shape_metadata(q.body,shape_idx++,Vector2(E->key().x,E->key().y)); } } + if (debug_shapes) { + vs->canvas_item_add_set_transform(canvas_item,Matrix32()); + } if (navigation) { Ref<NavigationPolygon> navpoly = tile_set->tile_get_navigation_polygon(c.id); @@ -412,6 +429,7 @@ void TileMap::_update_dirty_quadrants() { xform.set_origin(offset.floor()+q.pos); _fix_cell_transform(xform,c,npoly_ofs+center_ofs,s); + int pid = navigation->navpoly_create(navpoly,nav_rel * xform); Quadrant::NavPoly np; diff --git a/scene/3d/body_shape.cpp b/scene/3d/body_shape.cpp index c49d1b028c..b54cbfe0f9 100644 --- a/scene/3d/body_shape.cpp +++ b/scene/3d/body_shape.cpp @@ -43,7 +43,10 @@ void CollisionShape::_update_body() { - + if (!is_inside_tree() || !can_update_body) + return; + if (!get_tree()->is_editor_hint()) + return; if (get_parent() && get_parent()->cast_to<CollisionObject>()) get_parent()->cast_to<CollisionObject>()->_update_shapes_from_children(); @@ -310,10 +313,13 @@ void CollisionShape::_add_to_collision_object(Object* p_cshape) { if (shape.is_valid()) { + update_shape_index=co->get_shape_count(); co->add_shape(shape,get_transform()); - if (trigger) - co->set_shape_as_trigger( co->get_shape_count() -1, true ); - } + if (trigger) + co->set_shape_as_trigger( co->get_shape_count() -1, true ); + } else { + update_shape_index=-1; + } } void CollisionShape::_notification(int p_what) { @@ -322,12 +328,18 @@ void CollisionShape::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { unparenting=false; + can_update_body=get_tree()->is_editor_hint(); + set_notify_local_transform(!can_update_body); + + if (get_tree()->is_debugging_collisions_hint()) { + _create_debug_shape(); + } //indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); } break; case NOTIFICATION_TRANSFORM_CHANGED: { // VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform()); - if (updating_body) { + if (can_update_body && updating_body) { _update_body(); } } break; @@ -336,16 +348,34 @@ void CollisionShape::_notification(int p_what) { VisualServer::get_singleton()->free(indicator_instance); indicator_instance=RID(); }*/ + can_update_body=false; + set_notify_local_transform(false); + if (debug_shape) { + debug_shape->queue_delete(); + debug_shape=NULL; + } } break; case NOTIFICATION_UNPARENTED: { unparenting=true; - if (updating_body) + if (can_update_body && updating_body) _update_body(); } break; case NOTIFICATION_PARENTED: { - if (updating_body) + if (can_update_body && updating_body) _update_body(); } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + + if (!can_update_body && update_shape_index>=0) { + + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + co->set_shape_transform(update_shape_index,get_transform()); + } + } + + } break; + } } @@ -357,6 +387,18 @@ void CollisionShape::resource_changed(RES res) { } +void CollisionShape::_set_update_shape_index(int p_index) { + + + update_shape_index=p_index; +} + +int CollisionShape::_get_update_shape_index() const{ + + return update_shape_index; +} + + void CollisionShape::_bind_methods() { //not sure if this should do anything @@ -368,10 +410,14 @@ void CollisionShape::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionShape::is_trigger); ObjectTypeDB::bind_method(_MD("make_convex_from_brothers"),&CollisionShape::make_convex_from_brothers); ObjectTypeDB::set_method_flags("CollisionShape","make_convex_from_brothers",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::bind_method(_MD("_set_update_shape_index","index"),&CollisionShape::_set_update_shape_index); + ObjectTypeDB::bind_method(_MD("_get_update_shape_index"),&CollisionShape::_get_update_shape_index); + ObjectTypeDB::bind_method(_MD("get_collision_object_shape_index"),&CollisionShape::get_collision_object_shape_index); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape"), _SCS("set_shape"), _SCS("get_shape")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "_update_shape_index", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_NOEDITOR), _SCS("_set_update_shape_index"), _SCS("_get_update_shape_index")); } @@ -383,8 +429,15 @@ void CollisionShape::set_shape(const Ref<Shape> &p_shape) { if (!shape.is_null()) shape->register_owner(this); update_gizmo(); - if (updating_body) + if (updating_body) { _update_body(); + } else if (can_update_body && update_shape_index>=0 && is_inside_tree()){ + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + co->set_shape(update_shape_index,p_shape); + } + + } } Ref<Shape> CollisionShape::get_shape() const { @@ -405,8 +458,14 @@ bool CollisionShape::is_updating_body() const { void CollisionShape::set_trigger(bool p_trigger) { trigger=p_trigger; - if (updating_body) + if (updating_body) { _update_body(); + } else if (can_update_body && update_shape_index>=0 && is_inside_tree()){ + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + co->set_shape_as_trigger(update_shape_index,p_trigger); + } + } } bool CollisionShape::is_trigger() const{ @@ -419,7 +478,10 @@ CollisionShape::CollisionShape() { //indicator = VisualServer::get_singleton()->mesh_create(); updating_body=true; unparenting=false; - trigger=false; + update_shape_index=-1; + trigger=false; + can_update_body=false; + debug_shape=NULL; } CollisionShape::~CollisionShape() { @@ -428,6 +490,30 @@ CollisionShape::~CollisionShape() { //VisualServer::get_singleton()->free(indicator); } +void CollisionShape::_create_debug_shape() { + + + if (debug_shape) { + debug_shape->queue_delete();; + debug_shape=NULL; + } + + Ref<Shape> s = get_shape(); + + if (s.is_null()) + return; + + + Ref<Mesh> mesh = s->get_debug_mesh(); + + MeshInstance *mi = memnew( MeshInstance ); + mi->set_mesh(mesh); + + add_child(mi); + debug_shape=mi; + +} + #if 0 #include "body_volume.h" diff --git a/scene/3d/body_shape.h b/scene/3d/body_shape.h index b3c0006d79..6c0b89da56 100644 --- a/scene/3d/body_shape.h +++ b/scene/3d/body_shape.h @@ -50,14 +50,26 @@ class CollisionShape : public Spatial { RID indicator_instance; */ + Node* debug_shape; + void resource_changed(RES res); bool updating_body; bool unparenting; bool trigger; + bool can_update_body; + + int update_shape_index; + void _update_body(); void _add_to_collision_object(Object* p_cshape); + + void _set_update_shape_index(int p_index); + int _get_update_shape_index() const; + + void _create_debug_shape(); + protected: void _notification(int p_what); @@ -73,8 +85,10 @@ public: void set_updating_body(bool p_update); bool is_updating_body() const; - void set_trigger(bool p_trigger); - bool is_trigger() const; + void set_trigger(bool p_trigger); + bool is_trigger() const; + + int get_collision_object_shape_index() const { return _get_update_shape_index(); } CollisionShape(); ~CollisionShape(); diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index 4ab1a1a1ab..c857b4851a 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -6,6 +6,8 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { + if (!can_update_body) + return; CollisionObject *co = p_obj->cast_to<CollisionObject>(); ERR_FAIL_COND(!co); @@ -23,6 +25,7 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { //here comes the sun, lalalala //decompose concave into multiple convex polygons and add them + shape_from=co->get_shape_count(); for(int i=0;i<decomp.size();i++) { Ref<ConvexPolygonShape> convex = memnew( ConvexPolygonShape ); DVector<Vector3> cp; @@ -43,6 +46,11 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { co->add_shape(convex,get_transform()); } + shape_to=co->get_shape_count()-1; + if (shape_to<shape_from) { + shape_from=-1; + shape_to=-1; + } } else { #if 0 @@ -71,6 +79,9 @@ void CollisionPolygon::_add_to_collision_object(Object *p_obj) { void CollisionPolygon::_update_parent() { + if (!can_update_body) + return; + Node *parent = get_parent(); if (!parent) return; @@ -80,15 +91,50 @@ void CollisionPolygon::_update_parent() { co->_update_shapes_from_children(); } +void CollisionPolygon::_set_shape_range(const Vector2& p_range) { + + shape_from=p_range.x; + shape_to=p_range.y; +} + +Vector2 CollisionPolygon::_get_shape_range() const { + + return Vector2(shape_from,shape_to); +} + void CollisionPolygon::_notification(int p_what) { switch(p_what) { + case NOTIFICATION_ENTER_TREE: { + can_update_body=get_tree()->is_editor_hint(); + set_notify_local_transform(!can_update_body); + + //indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); + } break; + case NOTIFICATION_EXIT_TREE: { + can_update_body=false; + set_notify_local_transform(false); + } break; case NOTIFICATION_TRANSFORM_CHANGED: { if (!is_inside_tree()) break; - _update_parent(); + if (can_update_body) { + _update_parent(); + } + + } break; + case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { + if (!can_update_body && shape_from>=0 && shape_from>=0) { + + CollisionObject *co = get_parent()->cast_to<CollisionObject>(); + if (co) { + for(int i=shape_from;i<=shape_to;i++) { + co->set_shape_transform(i,get_transform()); + } + } + } } break; #if 0 @@ -119,29 +165,31 @@ void CollisionPolygon::_notification(int p_what) { void CollisionPolygon::set_polygon(const Vector<Point2>& p_polygon) { polygon=p_polygon; + if (can_update_body) { - for(int i=0;i<polygon.size();i++) { + for(int i=0;i<polygon.size();i++) { - Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5); + Vector3 p1(polygon[i].x,polygon[i].y,depth*0.5); - if (i==0) - aabb=AABB(p1,Vector3()); - else - aabb.expand_to(p1); + if (i==0) + aabb=AABB(p1,Vector3()); + else + aabb.expand_to(p1); - Vector3 p2(polygon[i].x,polygon[i].y,-depth*0.5); - aabb.expand_to(p2); + Vector3 p2(polygon[i].x,polygon[i].y,-depth*0.5); + aabb.expand_to(p2); - } - if (aabb==AABB()) { + } + if (aabb==AABB()) { - aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); - } else { - aabb.pos-=aabb.size*0.3; - aabb.size+=aabb.size*0.6; + aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); + } else { + aabb.pos-=aabb.size*0.3; + aabb.size+=aabb.size*0.6; + } + _update_parent(); } - _update_parent(); update_gizmo(); } @@ -154,6 +202,8 @@ void CollisionPolygon::set_build_mode(BuildMode p_mode) { ERR_FAIL_INDEX(p_mode,2); build_mode=p_mode; + if (!can_update_body) + return; _update_parent(); } @@ -170,6 +220,8 @@ AABB CollisionPolygon::get_item_rect() const { void CollisionPolygon::set_depth(float p_depth) { depth=p_depth; + if (!can_update_body) + return; _update_parent(); update_gizmo(); } @@ -183,22 +235,34 @@ float CollisionPolygon::get_depth() const { void CollisionPolygon::_bind_methods() { ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon::_add_to_collision_object); - ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon::set_polygon); - ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon::get_polygon); + + ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon::set_build_mode); + ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon::get_build_mode); ObjectTypeDB::bind_method(_MD("set_depth","depth"),&CollisionPolygon::set_depth); ObjectTypeDB::bind_method(_MD("get_depth"),&CollisionPolygon::get_depth); - ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon::set_build_mode); - ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon::get_build_mode); + ObjectTypeDB::bind_method(_MD("set_polygon","polygon"),&CollisionPolygon::set_polygon); + ObjectTypeDB::bind_method(_MD("get_polygon"),&CollisionPolygon::get_polygon); + + ObjectTypeDB::bind_method(_MD("_set_shape_range","shape_range"),&CollisionPolygon::_set_shape_range); + ObjectTypeDB::bind_method(_MD("_get_shape_range"),&CollisionPolygon::_get_shape_range); + + ObjectTypeDB::bind_method(_MD("get_collision_object_first_shape"),&CollisionPolygon::get_collision_object_first_shape); + ObjectTypeDB::bind_method(_MD("get_collision_object_last_shape"),&CollisionPolygon::get_collision_object_last_shape); ADD_PROPERTY( PropertyInfo(Variant::INT,"build_mode",PROPERTY_HINT_ENUM,"Solids,Triangles"),_SCS("set_build_mode"),_SCS("get_build_mode")); - ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"depth"),_SCS("set_depth"),_SCS("get_depth")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2_ARRAY,"polygon"),_SCS("set_polygon"),_SCS("get_polygon")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"shape_range",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_shape_range"),_SCS("_get_shape_range")); } CollisionPolygon::CollisionPolygon() { + shape_from=-1; + shape_to=-1; + can_update_body=false; + aabb=AABB(Vector3(-1,-1,-1),Vector3(2,2,2)); build_mode=BUILD_SOLIDS; depth=1.0; diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h index efb3666778..9b9afea34f 100644 --- a/scene/3d/collision_polygon.h +++ b/scene/3d/collision_polygon.h @@ -24,9 +24,17 @@ protected: BuildMode build_mode; Vector<Point2> polygon; + void _add_to_collision_object(Object *p_obj); void _update_parent(); + bool can_update_body; + int shape_from; + int shape_to; + + void _set_shape_range(const Vector2& p_range); + Vector2 _get_shape_range() const; + protected: void _notification(int p_what); @@ -43,6 +51,10 @@ public: Vector<Point2> get_polygon() const; virtual AABB get_item_rect() const; + + int get_collision_object_first_shape() const { return shape_from; } + int get_collision_object_last_shape() const { return shape_to; } + CollisionPolygon(); }; diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index bfa8add09c..ce28350be0 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -295,12 +295,14 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector } } + if (!begin_poly || !end_poly) { //print_line("No Path Path"); return Vector<Vector3>(); //no path } + if (begin_poly==end_poly) { Vector<Vector3> path; diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index 8c52d4c35c..a238a8ff22 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -1,6 +1,6 @@ #include "navigation_mesh.h" #include "navigation.h" - +#include "mesh_instance.h" void NavigationMesh::create_from_mesh(const Ref<Mesh>& p_mesh) { @@ -87,6 +87,97 @@ void NavigationMesh::clear_polygons(){ polygons.clear(); } +Ref<Mesh> NavigationMesh::get_debug_mesh() { + + if (debug_mesh.is_valid()) + return debug_mesh; + + + + DVector<Vector3> vertices = get_vertices(); + DVector<Vector3>::Read vr=vertices.read(); + List<Face3> faces; + for(int i=0;i<get_polygon_count();i++) { + Vector<int> p = get_polygon(i); + + for(int j=2;j<p.size();j++) { + Face3 f; + f.vertex[0]=vr[p[0]]; + f.vertex[1]=vr[p[j-1]]; + f.vertex[2]=vr[p[j]]; + + faces.push_back(f); + } + } + + + Map<_EdgeKey,bool> edge_map; + DVector<Vector3> tmeshfaces; + tmeshfaces.resize(faces.size()*3); + + { + DVector<Vector3>::Write tw=tmeshfaces.write(); + int tidx=0; + + + for(List<Face3>::Element *E=faces.front();E;E=E->next()) { + + const Face3 &f = E->get(); + + for(int j=0;j<3;j++) { + + tw[tidx++]=f.vertex[j]; + _EdgeKey ek; + ek.from=f.vertex[j].snapped(CMP_EPSILON); + ek.to=f.vertex[(j+1)%3].snapped(CMP_EPSILON); + if (ek.from<ek.to) + SWAP(ek.from,ek.to); + + Map<_EdgeKey,bool>::Element *E=edge_map.find(ek); + + if (E) { + + E->get()=false; + + } else { + + edge_map[ek]=true; + } + + } + } + } + List<Vector3> lines; + + for(Map<_EdgeKey,bool>::Element *E=edge_map.front();E;E=E->next()) { + + if (E->get()) { + lines.push_back(E->key().from); + lines.push_back(E->key().to); + } + } + + DVector<Vector3> varr; + varr.resize(lines.size()); + { + DVector<Vector3>::Write w = varr.write(); + int idx=0; + for(List<Vector3>::Element *E=lines.front();E;E=E->next()) { + w[idx++]=E->get(); + } + } + + debug_mesh = Ref<Mesh>( memnew( Mesh ) ); + + Array arr; + arr.resize(Mesh::ARRAY_MAX); + arr[Mesh::ARRAY_VERTEX]=varr; + + debug_mesh->add_surface(Mesh::PRIMITIVE_LINES,arr); + + return debug_mesh; +} + void NavigationMesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_vertices","vertices"),&NavigationMesh::set_vertices); @@ -135,6 +226,16 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) { } + if (debug_view) { + MeshInstance *dm=debug_view->cast_to<MeshInstance>(); + if (is_enabled()) { + dm->set_material_override( get_tree()->get_debug_navigation_material() ); + } else { + dm->set_material_override( get_tree()->get_debug_navigation_disabled_material() ); + } + + } + update_gizmo(); } @@ -170,6 +271,19 @@ void NavigationMeshInstance::_notification(int p_what) { c=c->get_parent_spatial(); } + if (navmesh.is_valid() && get_tree()->is_debugging_navigation_hint()) { + + MeshInstance *dm = memnew( MeshInstance ); + dm->set_mesh( navmesh->get_debug_mesh() ); + if (is_enabled()) { + dm->set_material_override( get_tree()->get_debug_navigation_material() ); + } else { + dm->set_material_override( get_tree()->get_debug_navigation_disabled_material() ); + } + add_child(dm); + debug_view=dm; + } + } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -177,6 +291,8 @@ void NavigationMeshInstance::_notification(int p_what) { navigation->navmesh_set_transform(nav_id,get_relative_transform(navigation)); } + + } break; case NOTIFICATION_EXIT_TREE: { @@ -187,6 +303,11 @@ void NavigationMeshInstance::_notification(int p_what) { nav_id=-1; } } + + if (debug_view) { + debug_view->queue_delete(); + debug_view=NULL; + } navigation=NULL; } break; } @@ -230,6 +351,7 @@ void NavigationMeshInstance::_bind_methods() { NavigationMeshInstance::NavigationMeshInstance() { + debug_view=NULL; navigation=NULL; nav_id=-1; enabled=true; diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h index fccf405f9d..1e53b2127a 100644 --- a/scene/3d/navigation_mesh.h +++ b/scene/3d/navigation_mesh.h @@ -4,6 +4,7 @@ #include "scene/3d/spatial.h" #include "scene/resources/mesh.h" +class Mesh; class NavigationMesh : public Resource { @@ -14,6 +15,16 @@ class NavigationMesh : public Resource { Vector<int> indices; }; Vector<Polygon> polygons; + Ref<Mesh> debug_mesh; + + struct _EdgeKey { + + Vector3 from; + Vector3 to; + + bool operator<(const _EdgeKey& p_with) const { return from==p_with.from ? to < p_with.to : from < p_with.from; } + }; + protected: @@ -21,6 +32,7 @@ protected: void _set_polygons(const Array& p_array); Array _get_polygons() const; + public: void create_from_mesh(const Ref<Mesh>& p_mesh); @@ -33,6 +45,8 @@ public: Vector<int> get_polygon(int p_idx); void clear_polygons(); + Ref<Mesh> get_debug_mesh(); + NavigationMesh(); }; @@ -47,6 +61,9 @@ class NavigationMeshInstance : public Spatial { int nav_id; Navigation *navigation; Ref<NavigationMesh> navmesh; + + Node *debug_view; + protected: void _notification(int p_what); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 9df29f70ec..4712ba308a 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -187,30 +187,59 @@ void Skeleton::_notification(int p_what) { Bone &b=bonesptr[i]; - if (b.enabled) { + if (b.disable_rest) { + if (b.enabled) { - Transform pose=b.pose; - if (b.custom_pose_enable) { + Transform pose=b.pose; + if (b.custom_pose_enable) { - pose = b.custom_pose * pose; - } + pose = b.custom_pose * pose; + } + + if (b.parent>=0) { + + b.pose_global=bonesptr[b.parent].pose_global * pose; + } else { - if (b.parent>=0) { - - b.pose_global=bonesptr[b.parent].pose_global * (b.rest * pose); + b.pose_global=pose; + } } else { - - b.pose_global=b.rest * pose; + + if (b.parent>=0) { + + b.pose_global=bonesptr[b.parent].pose_global; + } else { + + b.pose_global=Transform(); + } } + } else { - - if (b.parent>=0) { - - b.pose_global=bonesptr[b.parent].pose_global * b.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 * (b.rest * pose); + } else { + + b.pose_global=b.rest * pose; + } } else { - - b.pose_global=b.rest; - } + + if (b.parent>=0) { + + b.pose_global=bonesptr[b.parent].pose_global * b.rest; + } else { + + b.pose_global=b.rest; + } + } } vs->skeleton_bone_set_transform( skeleton, i, b.pose_global * b.rest_global_inverse ); @@ -315,6 +344,37 @@ void Skeleton::set_bone_parent(int p_bone, int p_parent) { _make_dirty(); } +void Skeleton::unparent_bone_and_rest(int p_bone) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + + int parent=bones[p_bone].parent; + while(parent>=0) { + bones[p_bone].rest = bones[parent].rest * bones[p_bone].rest; + parent=bones[parent].parent; + } + + bones[p_bone].parent=-1; + bones[p_bone].rest_global_inverse=bones[p_bone].rest.affine_inverse(); //same thing + + _make_dirty(); + +} + +void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) { + + ERR_FAIL_INDEX( p_bone, bones.size() ); + bones[p_bone].disable_rest=p_disable; + +} + +bool Skeleton::is_bone_rest_disabled(int p_bone) const { + + ERR_FAIL_INDEX_V( p_bone, bones.size(), false ); + return bones[p_bone].disable_rest; +} + + int Skeleton::get_bone_parent(int p_bone) const { ERR_FAIL_INDEX_V( p_bone, bones.size(), -1 ); @@ -522,9 +582,14 @@ void Skeleton::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_bone_count"),&Skeleton::get_bone_count); + ObjectTypeDB::bind_method(_MD("unparent_bone_and_rest","bone_idx"),&Skeleton::unparent_bone_and_rest); + ObjectTypeDB::bind_method(_MD("get_bone_rest","bone_idx"),&Skeleton::get_bone_rest); ObjectTypeDB::bind_method(_MD("set_bone_rest","bone_idx","rest"),&Skeleton::set_bone_rest); + ObjectTypeDB::bind_method(_MD("set_bone_disable_rest","bone_idx","disable"),&Skeleton::set_bone_disable_rest); + ObjectTypeDB::bind_method(_MD("is_bone_rest_disabled","bone_idx"),&Skeleton::is_bone_rest_disabled); + ObjectTypeDB::bind_method(_MD("bind_child_node_to_bone","bone_idx","node:Node"),&Skeleton::bind_child_node_to_bone); ObjectTypeDB::bind_method(_MD("unbind_child_node_from_bone","bone_idx","node:Node"),&Skeleton::unbind_child_node_from_bone); ObjectTypeDB::bind_method(_MD("get_bound_child_nodes_to_bone","bone_idx"),&Skeleton::_get_bound_child_nodes_to_bone); diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index b7f84f44c9..6678722d12 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -46,6 +46,7 @@ class Skeleton : public Spatial { bool enabled; int parent; + bool disable_rest; Transform rest; Transform rest_global_inverse; @@ -57,7 +58,7 @@ class Skeleton : public Spatial { List<uint32_t> nodes_bound; - Bone() { parent=-1; enabled=true; custom_pose_enable=false; } + Bone() { parent=-1; enabled=true; custom_pose_enable=false; disable_rest=false; } }; bool rest_global_inverse_dirty; @@ -111,6 +112,11 @@ public: void set_bone_parent(int p_bone, int p_parent); int get_bone_parent(int p_bone) const; + void unparent_bone_and_rest(int p_idx); + + void set_bone_disable_rest(int p_bone, bool p_disable); + bool is_bone_rest_disabled(int p_bone) const; + int get_bone_count() const; void set_bone_rest(int p_bone, const Transform& p_rest); diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index 7117c59176..a65f68ed2c 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -231,6 +231,11 @@ void Spatial::set_transform(const Transform& p_transform) { _change_notify("transform/rotation"); _change_notify("transform/scale"); _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } + + } @@ -335,6 +340,9 @@ void Spatial::set_translation(const Vector3& p_translation) { data.local_transform.origin=p_translation; _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } @@ -348,6 +356,9 @@ void Spatial::set_rotation(const Vector3& p_euler){ data.rotation=p_euler; data.dirty|=DIRTY_LOCAL; _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } void Spatial::set_scale(const Vector3& p_scale){ @@ -360,6 +371,9 @@ void Spatial::set_scale(const Vector3& p_scale){ data.scale=p_scale; data.dirty|=DIRTY_LOCAL; _propagate_transform_changed(this); + if (data.notify_local_transform) { + notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); + } } @@ -685,6 +699,13 @@ void Spatial::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, con } +void Spatial::set_notify_local_transform(bool p_enable) { + data.notify_local_transform=p_enable; +} + +bool Spatial::is_local_transform_notification_enabled() const { + return data.notify_local_transform; +} void Spatial::_bind_methods() { @@ -725,6 +746,9 @@ void Spatial::_bind_methods() { ObjectTypeDB::bind_method(_MD("_set_visible_"), &Spatial::_set_visible_); ObjectTypeDB::bind_method(_MD("_is_visible_"), &Spatial::_is_visible_); + ObjectTypeDB::bind_method(_MD("set_notify_local_transform","enable"), &Spatial::set_notify_local_transform); + ObjectTypeDB::bind_method(_MD("is_local_transform_notification_enabled"), &Spatial::is_local_transform_notification_enabled); + void rotate(const Vector3& p_normal,float p_radians); void rotate_x(float p_radians); void rotate_y(float p_radians); @@ -783,6 +807,7 @@ Spatial::Spatial() : xform_change(this) data.gizmo_disabled=false; data.gizmo_dirty=false; #endif + data.notify_local_transform=false; data.parent=NULL; data.C=NULL; diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 8b40786fb8..7fa6099d7a 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -91,6 +91,7 @@ class Spatial : public Node { List<Spatial*>::Element *C; bool ignore_notification; + bool notify_local_transform; bool visible; @@ -134,6 +135,7 @@ public: NOTIFICATION_ENTER_WORLD=41, NOTIFICATION_EXIT_WORLD=42, NOTIFICATION_VISIBILITY_CHANGED=43, + NOTIFICATION_LOCAL_TRANSFORM_CHANGED=44, }; Spatial *get_parent_spatial() const; @@ -179,6 +181,9 @@ public: void look_at(const Vector3& p_target, const Vector3& p_up_normal); void look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, const Vector3& p_up_normal); + void set_notify_local_transform(bool p_enable); + bool is_local_transform_notification_enabled() const; + void orthonormalize(); void set_identity(); diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp index 84e68bf418..346e354df2 100644 --- a/scene/3d/spatial_stream_player.cpp +++ b/scene/3d/spatial_stream_player.cpp @@ -30,21 +30,79 @@ -void SpatialStreamPlayer::_notification(int p_what) { +int SpatialStreamPlayer::InternalStream::get_channel_count() const { - switch(p_what) { + return player->sp_get_channel_count(); +} +void SpatialStreamPlayer::InternalStream::set_mix_rate(int p_rate){ - case NOTIFICATION_ENTER_WORLD: { + return player->sp_set_mix_rate(p_rate); +} +bool SpatialStreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){ + + return player->sp_mix(p_buffer,p_frames); +} +void SpatialStreamPlayer::InternalStream::update(){ + + player->sp_update(); +} + + +int SpatialStreamPlayer::sp_get_channel_count() const { + + return playback->get_channels(); +} + +void SpatialStreamPlayer::sp_set_mix_rate(int p_rate){ + + server_mix_rate=p_rate; +} + +bool SpatialStreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) { + + if (resampler.is_ready()) { + return resampler.mix(p_buffer,p_frames); + } + + return false; +} + +void SpatialStreamPlayer::sp_update() { + + _THREAD_SAFE_METHOD_ + if (!paused && resampler.is_ready() && playback.is_valid()) { + + if (!playback->is_playing()) { + //stream depleted data, but there's still audio in the ringbuffer + //check that all this audio has been flushed before stopping the stream + int to_mix = resampler.get_total() - resampler.get_todo(); + if (to_mix==0) { + stop(); + return; + } + + return; + } + + int todo =resampler.get_todo(); + int wrote = playback->mix(resampler.get_write_buffer(),todo); + resampler.write(wrote); + } +} -// set_idle_process(false); //don't annoy - } break; - case NOTIFICATION_PROCESS: { -// if (!stream.is_null()) -// stream->update(); +void SpatialStreamPlayer::_notification(int p_what) { + + switch(p_what) { + + case NOTIFICATION_ENTER_TREE: { + + //set_idle_process(false); //don't annoy + if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint()) + play(); } break; - case NOTIFICATION_EXIT_WORLD: { + case NOTIFICATION_EXIT_TREE: { stop(); //wathever it may be doing, stop } break; @@ -58,12 +116,20 @@ void SpatialStreamPlayer::set_stream(const Ref<AudioStream> &p_stream) { stop(); stream=p_stream; - if (!stream.is_null()) { - stream->set_loop(loops); + if (!stream.is_null()) { + playback=stream->instance_playback(); + playback->set_loop(loops); + playback->set_loop_restart_time(loop_point); + AudioServer::get_singleton()->lock(); + resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size()); + AudioServer::get_singleton()->unlock(); + } else { + AudioServer::get_singleton()->lock(); + resampler.clear(); + playback.unref(); + AudioServer::get_singleton()->unlock(); } - - } Ref<AudioStream> SpatialStreamPlayer::get_stream() const { @@ -72,18 +138,25 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const { } -void SpatialStreamPlayer::play() { +void SpatialStreamPlayer::play(float p_from_offset) { - if (!is_inside_tree()) + ERR_FAIL_COND(!is_inside_tree()); + if (playback.is_null()) return; - if (stream.is_null()) - return; - if (stream->is_playing()) + if (playback->is_playing()) stop(); - stream->play(); - SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),stream->get_audio_stream()); - //if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) - // set_idle_process(true); + + _THREAD_SAFE_METHOD_ + playback->play(p_from_offset); + //feed the ringbuffer as long as no update callback is going on + sp_update(); + + SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),&internal_stream); + +// AudioServer::get_singleton()->stream_set_active(stream_rid,true); +// AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); +// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) +// set_idle_process(true); } @@ -91,28 +164,30 @@ void SpatialStreamPlayer::stop() { if (!is_inside_tree()) return; - if (stream.is_null()) + if (playback.is_null()) return; + _THREAD_SAFE_METHOD_ + //AudioServer::get_singleton()->stream_set_active(stream_rid,false); SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL); - stream->stop(); + playback->stop(); //set_idle_process(false); } bool SpatialStreamPlayer::is_playing() const { - if (stream.is_null()) + if (playback.is_null()) return false; - return stream->is_playing(); + return playback->is_playing(); } void SpatialStreamPlayer::set_loop(bool p_enable) { loops=p_enable; - if (stream.is_null()) + if (playback.is_null()) return; - stream->set_loop(loops); + playback->set_loop(loops); } bool SpatialStreamPlayer::has_loop() const { @@ -120,6 +195,46 @@ bool SpatialStreamPlayer::has_loop() const { return loops; } +void SpatialStreamPlayer::set_volume(float p_vol) { + + volume=p_vol; + if (stream_rid.is_valid()) + AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); +} + +float SpatialStreamPlayer::get_volume() const { + + return volume; +} + +void SpatialStreamPlayer::set_loop_restart_time(float p_secs) { + + loop_point=p_secs; + if (playback.is_valid()) + playback->set_loop_restart_time(p_secs); +} + +float SpatialStreamPlayer::get_loop_restart_time() const { + + return loop_point; +} + + +void SpatialStreamPlayer::set_volume_db(float p_db) { + + if (p_db<-79) + set_volume(0); + else + set_volume(Math::db2linear(p_db)); +} + +float SpatialStreamPlayer::get_volume_db() const { + + if (volume==0) + return -80; + else + return Math::linear2db(volume); +} String SpatialStreamPlayer::get_stream_name() const { @@ -132,59 +247,156 @@ String SpatialStreamPlayer::get_stream_name() const { int SpatialStreamPlayer::get_loop_count() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_loop_count(); + return playback->get_loop_count(); } float SpatialStreamPlayer::get_pos() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_pos(); + return playback->get_pos(); + +} + +float SpatialStreamPlayer::get_length() const { + if (playback.is_null()) + return 0; + return playback->get_length(); } void SpatialStreamPlayer::seek_pos(float p_time) { - if (stream.is_null()) + if (playback.is_null()) return; - return stream->seek_pos(p_time); + return playback->seek_pos(p_time); + +} + +void SpatialStreamPlayer::set_autoplay(bool p_enable) { + + autoplay=p_enable; +} + +bool SpatialStreamPlayer::has_autoplay() const { + + return autoplay; +} + +void SpatialStreamPlayer::set_paused(bool p_paused) { + + paused=p_paused; + //if (stream.is_valid()) + // stream->set_paused(p_paused); +} + +bool SpatialStreamPlayer::is_paused() const { + return paused; } +void SpatialStreamPlayer::_set_play(bool p_play) { + + _play=p_play; + if (is_inside_tree()) { + if(_play) + play(); + else + stop(); + } + +} + +bool SpatialStreamPlayer::_get_play() const{ + + return _play; +} + +void SpatialStreamPlayer::set_buffering_msec(int p_msec) { + + buffering_ms=p_msec; +} + +int SpatialStreamPlayer::get_buffering_msec() const{ + + return buffering_ms; +} + + + void SpatialStreamPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream); ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&SpatialStreamPlayer::get_stream); - ObjectTypeDB::bind_method(_MD("play"),&SpatialStreamPlayer::play); + ObjectTypeDB::bind_method(_MD("play"),&SpatialStreamPlayer::play,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("stop"),&SpatialStreamPlayer::stop); ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing); + ObjectTypeDB::bind_method(_MD("set_paused","paused"),&SpatialStreamPlayer::set_paused); + ObjectTypeDB::bind_method(_MD("is_paused"),&SpatialStreamPlayer::is_paused); + ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop); ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop); + ObjectTypeDB::bind_method(_MD("set_volume","volume"),&SpatialStreamPlayer::set_volume); + ObjectTypeDB::bind_method(_MD("get_volume"),&SpatialStreamPlayer::get_volume); + + ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&SpatialStreamPlayer::set_volume_db); + ObjectTypeDB::bind_method(_MD("get_volume_db"),&SpatialStreamPlayer::get_volume_db); + + ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&SpatialStreamPlayer::set_buffering_msec); + ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&SpatialStreamPlayer::get_buffering_msec); + + ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&SpatialStreamPlayer::set_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&SpatialStreamPlayer::get_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count); ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos); ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos); - ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"),_SCS("get_stream") ); - ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"),_SCS("has_loop") ); + ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&SpatialStreamPlayer::set_autoplay); + ObjectTypeDB::bind_method(_MD("has_autoplay"),&SpatialStreamPlayer::has_autoplay); + ObjectTypeDB::bind_method(_MD("get_length"),&SpatialStreamPlayer::get_length); + + ObjectTypeDB::bind_method(_MD("_set_play","play"),&SpatialStreamPlayer::_set_play); + ObjectTypeDB::bind_method(_MD("_get_play"),&SpatialStreamPlayer::_get_play); + + ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"), _SCS("get_stream") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/play"), _SCS("_set_play"), _SCS("_get_play") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") ); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") ); } SpatialStreamPlayer::SpatialStreamPlayer() { + volume=1; loops=false; + paused=false; + autoplay=false; + _play=false; + server_mix_rate=1; + internal_stream.player=this; + stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream); + buffering_ms=500; + loop_point=0; + } SpatialStreamPlayer::~SpatialStreamPlayer() { - -} + AudioServer::get_singleton()->free(stream_rid); + resampler.clear(); +} diff --git a/scene/3d/spatial_stream_player.h b/scene/3d/spatial_stream_player.h index 7e639a7232..f2775a4982 100644 --- a/scene/3d/spatial_stream_player.h +++ b/scene/3d/spatial_stream_player.h @@ -31,16 +31,48 @@ #include "scene/resources/audio_stream.h" #include "scene/3d/spatial_player.h" - +#include "servers/audio/audio_rb_resampler.h" class SpatialStreamPlayer : public SpatialPlayer { OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer); + _THREAD_SAFE_CLASS_ + + struct InternalStream : public AudioServer::AudioStream { + SpatialStreamPlayer *player; + virtual int get_channel_count() const; + virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate + virtual bool mix(int32_t *p_buffer,int p_frames); + virtual void update(); + }; + + + InternalStream internal_stream; + Ref<AudioStreamPlayback> playback; Ref<AudioStream> stream; + + int sp_get_channel_count() const; + void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate + bool sp_mix(int32_t *p_buffer,int p_frames); + void sp_update(); + + int server_mix_rate; + + RID stream_rid; + bool paused; + bool autoplay; bool loops; -protected: + float volume; + float loop_point; + int buffering_ms; + AudioRBResampler resampler; + + bool _play; + void _set_play(bool p_play); + bool _get_play() const; +protected: void _notification(int p_what); static void _bind_methods(); @@ -49,21 +81,37 @@ public: void set_stream(const Ref<AudioStream> &p_stream); Ref<AudioStream> get_stream() const; - void play(); + void play(float p_from_offset=0); void stop(); bool is_playing() const; + void set_paused(bool p_paused); + bool is_paused() const; + void set_loop(bool p_enable); bool has_loop() const; + void set_volume(float p_vol); + float get_volume() const; + + void set_loop_restart_time(float p_secs); + float get_loop_restart_time() const; + + void set_volume_db(float p_db); + float get_volume_db() const; String get_stream_name() const; - int get_loop_count() const; + int get_loop_count() const; float get_pos() const; void seek_pos(float p_time); + float get_length() const; + void set_autoplay(bool p_vol); + bool has_autoplay() const; + void set_buffering_msec(int p_msec); + int get_buffering_msec() const; SpatialStreamPlayer(); ~SpatialStreamPlayer(); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index f8b58b5cb5..c2ea1c8bb6 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -857,6 +857,11 @@ void AnimationPlayer::clear_queue() { queued.clear(); }; +void AnimationPlayer::play_backwards(const StringName& p_name,float p_custom_blend) { + + play(p_name,p_custom_blend,-1,true); +} + void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float p_custom_scale,bool p_from_end) { //printf("animation is %ls\n", String(p_name).c_str()); @@ -1216,6 +1221,7 @@ void AnimationPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_default_blend_time"),&AnimationPlayer::get_default_blend_time); ObjectTypeDB::bind_method(_MD("play","name","custom_blend","custom_speed","from_end"),&AnimationPlayer::play,DEFVAL(""),DEFVAL(-1),DEFVAL(1.0),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("play_backwards","name","custom_blend"),&AnimationPlayer::play_backwards,DEFVAL(""),DEFVAL(-1)); ObjectTypeDB::bind_method(_MD("stop","reset"),&AnimationPlayer::stop,DEFVAL(true)); ObjectTypeDB::bind_method(_MD("stop_all"),&AnimationPlayer::stop_all); ObjectTypeDB::bind_method(_MD("is_playing"),&AnimationPlayer::is_playing); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 3fddc283ae..1e3c37c4d6 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -258,6 +258,7 @@ public: float get_default_blend_time() const; void play(const StringName& p_name=StringName(),float p_custom_blend=-1,float p_custom_scale=1.0,bool p_from_end=false); + void play_backwards(const StringName& p_name=StringName(),float p_custom_blend=-1); void queue(const StringName& p_name); void clear_queue(); void stop(bool p_reset=true); diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp index b93f7e7ddd..7c0a926324 100644 --- a/scene/audio/sample_player.cpp +++ b/scene/audio/sample_player.cpp @@ -48,8 +48,8 @@ bool SamplePlayer::_set(const StringName& p_name, const Variant& p_value) { } } else if (name=="config/samples") set_sample_library(p_value); - else if (name=="config/voices") - set_voice_count(p_value); + else if (name=="config/polyphony") + set_polyphony(p_value); else if (name.begins_with("default/")) { String what=name.right(8); @@ -95,14 +95,14 @@ bool SamplePlayer::_get(const StringName& p_name,Variant &r_ret) const { if (name=="play/play") { r_ret=played_back; - } else if (name=="config/voices") { - r_ret= get_voice_count(); + } else if (name=="config/polyphony") { + r_ret= get_polyphony(); } else if (name=="config/samples") { r_ret= get_sample_library(); } else if (name.begins_with("default/")) { - String what=name.get_slicec('/',1); + String what=name.right(8); if (what=="volume_db") r_ret= get_default_volume_db(); @@ -153,7 +153,7 @@ void SamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const { } p_list->push_back( PropertyInfo( Variant::STRING, "play/play", PROPERTY_HINT_ENUM, en,PROPERTY_USAGE_EDITOR)); - p_list->push_back( PropertyInfo( Variant::INT, "config/voices", PROPERTY_HINT_RANGE, "1,256,1")); + p_list->push_back( PropertyInfo( Variant::INT, "config/polyphony", PROPERTY_HINT_RANGE, "1,256,1")); p_list->push_back( PropertyInfo( Variant::OBJECT, "config/samples", PROPERTY_HINT_RESOURCE_TYPE, "SampleLibrary")); p_list->push_back( PropertyInfo( Variant::REAL, "default/volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01")); p_list->push_back( PropertyInfo( Variant::REAL, "default/pitch_scale", PROPERTY_HINT_RANGE, "0.01,48,0.01")); @@ -164,7 +164,7 @@ void SamplePlayer::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back( PropertyInfo( Variant::REAL, "default/filter/cutoff", PROPERTY_HINT_RANGE, "20,16384.0,0.01")); p_list->push_back( PropertyInfo( Variant::REAL, "default/filter/resonance", PROPERTY_HINT_RANGE, "0,4,0.01")); p_list->push_back( PropertyInfo( Variant::REAL, "default/filter/gain", PROPERTY_HINT_RANGE, "0,2,0.01")); - p_list->push_back( PropertyInfo( Variant::INT, "default/reverb_room", PROPERTY_HINT_ENUM, "Small,Medimum,Large,Hall")); + p_list->push_back( PropertyInfo( Variant::INT, "default/reverb_room", PROPERTY_HINT_ENUM, "Small,Medium,Large,Hall")); p_list->push_back( PropertyInfo( Variant::REAL, "default/reverb_send", PROPERTY_HINT_RANGE, "0,1,0.01")); p_list->push_back( PropertyInfo( Variant::REAL, "default/chorus_send", PROPERTY_HINT_RANGE, "0,1,0.01")); @@ -203,14 +203,14 @@ SamplePlayer::Voice::~Voice() { } -void SamplePlayer::set_voice_count(int p_voice_count) { +void SamplePlayer::set_polyphony(int p_voice_count) { ERR_FAIL_COND( p_voice_count <1 || p_voice_count >0xFFFE ); voices.resize(p_voice_count); } -int SamplePlayer::get_voice_count() const { +int SamplePlayer::get_polyphony() const { return voices.size(); } @@ -460,9 +460,9 @@ float SamplePlayer::get_chorus(VoiceID p_voice) const { return v.chorus_send; } -float SamplePlayer::get_reverb_room(VoiceID p_voice) const { +SamplePlayer::ReverbRoomType SamplePlayer::get_reverb_room(VoiceID p_voice) const { - _GET_VOICE_V(0); + _GET_VOICE_V(REVERB_SMALL); return v.reverb_room; } @@ -591,7 +591,7 @@ float SamplePlayer::get_default_chorus() const { return _default.chorus_send; } -float SamplePlayer::get_default_reverb_room() const { +SamplePlayer::ReverbRoomType SamplePlayer::get_default_reverb_room() const { return _default.reverb_room; } @@ -606,8 +606,8 @@ void SamplePlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_sample_library","library:SampleLibrary"),&SamplePlayer::set_sample_library ); ObjectTypeDB::bind_method(_MD("get_sample_library:SampleLibrary"),&SamplePlayer::get_sample_library ); - ObjectTypeDB::bind_method(_MD("set_voice_count","max_voices"),&SamplePlayer::set_voice_count ); - ObjectTypeDB::bind_method(_MD("get_voice_count"),&SamplePlayer::get_voice_count ); + ObjectTypeDB::bind_method(_MD("set_polyphony","max_voices"),&SamplePlayer::set_polyphony ); + ObjectTypeDB::bind_method(_MD("get_polyphony"),&SamplePlayer::get_polyphony ); ObjectTypeDB::bind_method(_MD("play","name","unique"),&SamplePlayer::play, DEFVAL(false) ); ObjectTypeDB::bind_method(_MD("stop","voice"),&SamplePlayer::stop ); @@ -615,8 +615,8 @@ void SamplePlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_mix_rate","voice","hz"),&SamplePlayer::set_mix_rate ); ObjectTypeDB::bind_method(_MD("set_pitch_scale","voice","ratio"),&SamplePlayer::set_pitch_scale ); - ObjectTypeDB::bind_method(_MD("set_volume","voice","nrg"),&SamplePlayer::set_volume ); - ObjectTypeDB::bind_method(_MD("set_volume_db","voice","nrg"),&SamplePlayer::set_volume_db ); + ObjectTypeDB::bind_method(_MD("set_volume","voice","volume"),&SamplePlayer::set_volume ); + ObjectTypeDB::bind_method(_MD("set_volume_db","voice","db"),&SamplePlayer::set_volume_db ); ObjectTypeDB::bind_method(_MD("set_pan","voice","pan","depth","height"),&SamplePlayer::set_pan,DEFVAL(0),DEFVAL(0) ); ObjectTypeDB::bind_method(_MD("set_filter","voice","type","cutoff_hz","resonance","gain"),&SamplePlayer::set_filter,DEFVAL(0) ); ObjectTypeDB::bind_method(_MD("set_chorus","voice","send"),&SamplePlayer::set_chorus ); @@ -638,8 +638,8 @@ void SamplePlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_reverb","voice"),&SamplePlayer::get_reverb ); ObjectTypeDB::bind_method(_MD("set_default_pitch_scale","ratio"),&SamplePlayer::set_default_pitch_scale ); - ObjectTypeDB::bind_method(_MD("set_default_volume","nrg"),&SamplePlayer::set_default_volume ); - ObjectTypeDB::bind_method(_MD("set_default_volume_db","db"),&SamplePlayer::set_default_volume ); + ObjectTypeDB::bind_method(_MD("set_default_volume","volume"),&SamplePlayer::set_default_volume ); + ObjectTypeDB::bind_method(_MD("set_default_volume_db","db"),&SamplePlayer::set_default_volume_db ); ObjectTypeDB::bind_method(_MD("set_default_pan","pan","depth","height"),&SamplePlayer::set_default_pan,DEFVAL(0),DEFVAL(0) ); ObjectTypeDB::bind_method(_MD("set_default_filter","type","cutoff_hz","resonance","gain"),&SamplePlayer::set_default_filter,DEFVAL(0) ); ObjectTypeDB::bind_method(_MD("set_default_chorus","send"),&SamplePlayer::set_default_chorus ); @@ -647,7 +647,7 @@ void SamplePlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_default_pitch_scale"),&SamplePlayer::get_default_pitch_scale ); ObjectTypeDB::bind_method(_MD("get_default_volume"),&SamplePlayer::get_default_volume ); - ObjectTypeDB::bind_method(_MD("get_default_volume_db"),&SamplePlayer::get_default_volume ); + ObjectTypeDB::bind_method(_MD("get_default_volume_db"),&SamplePlayer::get_default_volume_db ); ObjectTypeDB::bind_method(_MD("get_default_pan"),&SamplePlayer::get_default_pan ); ObjectTypeDB::bind_method(_MD("get_default_pan_depth"),&SamplePlayer::get_default_pan_depth ); ObjectTypeDB::bind_method(_MD("get_default_pan_height"),&SamplePlayer::get_default_pan_height ); @@ -677,6 +677,8 @@ void SamplePlayer::_bind_methods() { BIND_CONSTANT( REVERB_LARGE ); BIND_CONSTANT( REVERB_HALL ); + BIND_CONSTANT( INVALID_VOICE_ID ); + } diff --git a/scene/audio/sample_player.h b/scene/audio/sample_player.h index 53e085b8d8..75a01aff86 100644 --- a/scene/audio/sample_player.h +++ b/scene/audio/sample_player.h @@ -130,8 +130,8 @@ public: void set_sample_library(const Ref<SampleLibrary>& p_library); Ref<SampleLibrary> get_sample_library() const; - void set_voice_count(int p_voice_count); - int get_voice_count() const; + void set_polyphony(int p_voice_count); + int get_polyphony() const; VoiceID play(const String& p_name,bool unique=false); void stop(VoiceID p_voice); @@ -161,7 +161,7 @@ public: float get_filter_resonance(VoiceID p_voice) const; float get_filter_gain(VoiceID p_voice) const; float get_chorus(VoiceID p_voice) const; - float get_reverb_room(VoiceID p_voice) const; + ReverbRoomType get_reverb_room(VoiceID p_voice) const; float get_reverb(VoiceID p_voice) const; @@ -185,7 +185,7 @@ public: float get_default_filter_resonance() const; float get_default_filter_gain() const; float get_default_chorus() const; - float get_default_reverb_room() const; + ReverbRoomType get_default_reverb_room() const; float get_default_reverb() const; SamplePlayer(); diff --git a/scene/audio/stream_player.cpp b/scene/audio/stream_player.cpp index a097aacf19..0ee9d76611 100644 --- a/scene/audio/stream_player.cpp +++ b/scene/audio/stream_player.cpp @@ -28,6 +28,67 @@ /*************************************************************************/ #include "stream_player.h" +int StreamPlayer::InternalStream::get_channel_count() const { + + return player->sp_get_channel_count(); +} +void StreamPlayer::InternalStream::set_mix_rate(int p_rate){ + + return player->sp_set_mix_rate(p_rate); +} +bool StreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){ + + return player->sp_mix(p_buffer,p_frames); +} +void StreamPlayer::InternalStream::update(){ + + player->sp_update(); +} + + +int StreamPlayer::sp_get_channel_count() const { + + return playback->get_channels(); +} + +void StreamPlayer::sp_set_mix_rate(int p_rate){ + + server_mix_rate=p_rate; +} + +bool StreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) { + + if (resampler.is_ready()) { + return resampler.mix(p_buffer,p_frames); + } + + return false; +} + +void StreamPlayer::sp_update() { + + //_THREAD_SAFE_METHOD_ + if (!paused && resampler.is_ready() && playback.is_valid()) { + + if (!playback->is_playing()) { + //stream depleted data, but there's still audio in the ringbuffer + //check that all this audio has been flushed before stopping the stream + int to_mix = resampler.get_total() - resampler.get_todo(); + if (to_mix==0) { + stop(); + return; + } + + return; + } + + int todo =resampler.get_todo(); + int wrote = playback->mix(resampler.get_write_buffer(),todo); + resampler.write(wrote); + } +} + + void StreamPlayer::_notification(int p_what) { @@ -52,19 +113,21 @@ void StreamPlayer::set_stream(const Ref<AudioStream> &p_stream) { stop(); - if (stream_rid.is_valid()) - AudioServer::get_singleton()->free(stream_rid); - stream_rid=RID(); - stream=p_stream; - if (!stream.is_null()) { - stream->set_loop(loops); - stream->set_paused(paused); - stream_rid=AudioServer::get_singleton()->audio_stream_create(stream->get_audio_stream()); + if (!stream.is_null()) { + playback=stream->instance_playback(); + playback->set_loop(loops); + playback->set_loop_restart_time(loop_point); + AudioServer::get_singleton()->lock(); + resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size()); + AudioServer::get_singleton()->unlock(); + } else { + AudioServer::get_singleton()->lock(); + resampler.clear(); + playback.unref(); + AudioServer::get_singleton()->unlock(); } - - } Ref<AudioStream> StreamPlayer::get_stream() const { @@ -73,15 +136,18 @@ Ref<AudioStream> StreamPlayer::get_stream() const { } -void StreamPlayer::play() { +void StreamPlayer::play(float p_from_offset) { ERR_FAIL_COND(!is_inside_tree()); - if (stream.is_null()) + if (playback.is_null()) return; - if (stream->is_playing()) + if (playback->is_playing()) stop(); - stream->play(); + //_THREAD_SAFE_METHOD_ + playback->play(p_from_offset); + //feed the ringbuffer as long as no update callback is going on + sp_update(); AudioServer::get_singleton()->stream_set_active(stream_rid,true); AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); // if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) @@ -93,28 +159,29 @@ void StreamPlayer::stop() { if (!is_inside_tree()) return; - if (stream.is_null()) + if (playback.is_null()) return; + //_THREAD_SAFE_METHOD_ AudioServer::get_singleton()->stream_set_active(stream_rid,false); - stream->stop(); + playback->stop(); //set_idle_process(false); } bool StreamPlayer::is_playing() const { - if (stream.is_null()) + if (playback.is_null()) return false; - return stream->is_playing(); + return playback->is_playing(); } void StreamPlayer::set_loop(bool p_enable) { loops=p_enable; - if (stream.is_null()) + if (playback.is_null()) return; - stream->set_loop(loops); + playback->set_loop(loops); } bool StreamPlayer::has_loop() const { @@ -134,6 +201,19 @@ float StreamPlayer::get_volume() const { return volume; } +void StreamPlayer::set_loop_restart_time(float p_secs) { + + loop_point=p_secs; + if (playback.is_valid()) + playback->set_loop_restart_time(p_secs); +} + +float StreamPlayer::get_loop_restart_time() const { + + return loop_point; +} + + void StreamPlayer::set_volume_db(float p_db) { if (p_db<-79) @@ -161,31 +241,31 @@ String StreamPlayer::get_stream_name() const { int StreamPlayer::get_loop_count() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_loop_count(); + return playback->get_loop_count(); } float StreamPlayer::get_pos() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_pos(); + return playback->get_pos(); } float StreamPlayer::get_length() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_length(); + return playback->get_length(); } void StreamPlayer::seek_pos(float p_time) { - if (stream.is_null()) + if (playback.is_null()) return; - return stream->seek_pos(p_time); + return playback->seek_pos(p_time); } @@ -202,8 +282,8 @@ bool StreamPlayer::has_autoplay() const { void StreamPlayer::set_paused(bool p_paused) { paused=p_paused; - if (stream.is_valid()) - stream->set_paused(p_paused); + //if (stream.is_valid()) + // stream->set_paused(p_paused); } bool StreamPlayer::is_paused() const { @@ -228,13 +308,24 @@ bool StreamPlayer::_get_play() const{ return _play; } +void StreamPlayer::set_buffering_msec(int p_msec) { + + buffering_ms=p_msec; +} + +int StreamPlayer::get_buffering_msec() const{ + + return buffering_ms; +} + + void StreamPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&StreamPlayer::set_stream); ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&StreamPlayer::get_stream); - ObjectTypeDB::bind_method(_MD("play"),&StreamPlayer::play); + ObjectTypeDB::bind_method(_MD("play"),&StreamPlayer::play,DEFVAL(0)); ObjectTypeDB::bind_method(_MD("stop"),&StreamPlayer::stop); ObjectTypeDB::bind_method(_MD("is_playing"),&StreamPlayer::is_playing); @@ -251,6 +342,12 @@ void StreamPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&StreamPlayer::set_volume_db); ObjectTypeDB::bind_method(_MD("get_volume_db"),&StreamPlayer::get_volume_db); + ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&StreamPlayer::set_buffering_msec); + ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&StreamPlayer::get_buffering_msec); + + ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&StreamPlayer::set_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&StreamPlayer::get_loop_restart_time); + ObjectTypeDB::bind_method(_MD("get_stream_name"),&StreamPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_loop_count"),&StreamPlayer::get_loop_count); @@ -271,6 +368,8 @@ void StreamPlayer::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") ); } @@ -281,10 +380,17 @@ StreamPlayer::StreamPlayer() { paused=false; autoplay=false; _play=false; + server_mix_rate=1; + internal_stream.player=this; + stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream); + buffering_ms=500; + loop_point=0; + } StreamPlayer::~StreamPlayer() { - if (stream_rid.is_valid()) - AudioServer::get_singleton()->free(stream_rid); + AudioServer::get_singleton()->free(stream_rid); + resampler.clear(); + } diff --git a/scene/audio/stream_player.h b/scene/audio/stream_player.h index 21e2162188..be090f50e1 100644 --- a/scene/audio/stream_player.h +++ b/scene/audio/stream_player.h @@ -31,17 +31,43 @@ #include "scene/resources/audio_stream.h" #include "scene/main/node.h" +#include "servers/audio/audio_rb_resampler.h" class StreamPlayer : public Node { OBJ_TYPE(StreamPlayer,Node); + //_THREAD_SAFE_CLASS_ + + struct InternalStream : public AudioServer::AudioStream { + StreamPlayer *player; + virtual int get_channel_count() const; + virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate + virtual bool mix(int32_t *p_buffer,int p_frames); + virtual void update(); + }; + + + InternalStream internal_stream; + Ref<AudioStreamPlayback> playback; Ref<AudioStream> stream; + + int sp_get_channel_count() const; + void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate + bool sp_mix(int32_t *p_buffer,int p_frames); + void sp_update(); + + int server_mix_rate; + RID stream_rid; bool paused; bool autoplay; bool loops; float volume; + float loop_point; + int buffering_ms; + + AudioRBResampler resampler; bool _play; void _set_play(bool p_play); @@ -55,7 +81,7 @@ public: void set_stream(const Ref<AudioStream> &p_stream); Ref<AudioStream> get_stream() const; - void play(); + void play(float p_from_offset=0); void stop(); bool is_playing() const; @@ -68,6 +94,9 @@ public: void set_volume(float p_vol); float get_volume() const; + void set_loop_restart_time(float p_secs); + float get_loop_restart_time() const; + void set_volume_db(float p_db); float get_volume_db() const; @@ -81,6 +110,8 @@ public: void set_autoplay(bool p_vol); bool has_autoplay() const; + void set_buffering_msec(int p_msec); + int get_buffering_msec() const; StreamPlayer(); ~StreamPlayer(); diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index 965e7f399d..0c63a3bc74 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -255,6 +255,16 @@ void BaseButton::_notification(int p_what) { group->_remove_button(this); } + if (p_what==NOTIFICATION_VISIBILITY_CHANGED && !is_visible()) { + + if (!toggle_mode) { + status.pressed = false; + } + status.hovering = false; + status.press_attempt = false; + status.pressing_inside = false; + status.pressing_button = 0; + } } void BaseButton::pressed() { diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 6489cbccd5..b63b3de530 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -99,8 +99,10 @@ void BoxContainer::_resort() { elements exist */ + bool has_stretched = false; while(stretch_ratio_total>0) { // first of all, dont even be here if no stretchable objects exist + has_stretched = true; bool refit_successful=true; //assume refit-test will go well for(int i=0;i<get_child_count();i++) { @@ -143,6 +145,18 @@ void BoxContainer::_resort() { int ofs=0; + if (!has_stretched) { + switch (align) { + case ALIGN_BEGIN: + break; + case ALIGN_CENTER: + ofs = stretch_diff / 2; + break; + case ALIGN_END: + ofs = stretch_diff; + break; + } + } first=true; int idx=0; @@ -254,6 +268,15 @@ void BoxContainer::_notification(int p_what) { } } +void BoxContainer::set_alignment(AlignMode p_align) { + align = p_align; + _resort(); +} + +BoxContainer::AlignMode BoxContainer::get_alignment() const { + return align; +} + void BoxContainer::add_spacer(bool p_begin) { Control *c = memnew( Control ); @@ -270,10 +293,23 @@ void BoxContainer::add_spacer(bool p_begin) { BoxContainer::BoxContainer(bool p_vertical) { vertical=p_vertical; + align = ALIGN_BEGIN; // set_ignore_mouse(true); set_stop_mouse(false); } +void BoxContainer::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("get_alignment"),&BoxContainer::get_alignment); + ObjectTypeDB::bind_method(_MD("set_alignment","alignment"),&BoxContainer::set_alignment); + + BIND_CONSTANT( ALIGN_BEGIN ); + BIND_CONSTANT( ALIGN_CENTER ); + BIND_CONSTANT( ALIGN_END ); + + ADD_PROPERTY( PropertyInfo(Variant::INT,"alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), _SCS("set_alignment"),_SCS("get_alignment") ); + +} MarginContainer* VBoxContainer::add_margin_child(const String& p_label,Control *p_control,bool p_expand) { diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h index d461b4aebe..c357814baf 100644 --- a/scene/gui/box_container.h +++ b/scene/gui/box_container.h @@ -35,16 +35,31 @@ class BoxContainer : public Container { OBJ_TYPE(BoxContainer,Container); +public: + + enum AlignMode { + ALIGN_BEGIN, + ALIGN_CENTER, + ALIGN_END + }; + +private: bool vertical; + AlignMode align; void _resort(); protected: void _notification(int p_what); + + static void _bind_methods(); public: void add_spacer(bool p_begin=false); + void set_alignment(AlignMode p_align); + AlignMode get_alignment() const; + virtual Size2 get_minimum_size() const; BoxContainer(bool p_vertical=false); @@ -73,4 +88,6 @@ public: VBoxContainer() : BoxContainer(true) {} }; +VARIANT_ENUM_CAST(BoxContainer::AlignMode); + #endif // BOX_CONTAINER_H diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index b7b2f061ea..40fade840c 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -1025,7 +1025,7 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("get_item_text","idx"),&ItemList::get_item_text); ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon:Texture"),&ItemList::set_item_icon); - ObjectTypeDB::bind_method(_MD("get_item_icon:Tedture","idx"),&ItemList::get_item_icon); + ObjectTypeDB::bind_method(_MD("get_item_icon:Texture","idx"),&ItemList::get_item_icon); ObjectTypeDB::bind_method(_MD("set_item_selectable","idx","selectable"),&ItemList::set_item_selectable); ObjectTypeDB::bind_method(_MD("is_item_selectable","idx"),&ItemList::is_item_selectable); diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index e7af4fa349..002e49cbcf 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -33,15 +33,15 @@ void Label::set_autowrap(bool p_autowrap) { - + autowrap=p_autowrap; word_cache_dirty=true; minimum_size_changed(); - - + update(); + } bool Label::has_autowrap() const { - + return autowrap; } @@ -51,6 +51,7 @@ void Label::set_uppercase(bool p_uppercase) { uppercase=p_uppercase; word_cache_dirty=true; minimum_size_changed(); + update(); } bool Label::is_uppercase() const { @@ -66,19 +67,18 @@ int Label::get_line_height() const { void Label::_notification(int p_what) { - + if (p_what==NOTIFICATION_DRAW) { - - if (clip && !autowrap) - VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); + if (clip || autowrap) + VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); if (word_cache_dirty) regenerate_word_cache(); - + RID ci = get_canvas_item(); - + Size2 string_size; Size2 size=get_size(); @@ -91,38 +91,43 @@ void Label::_notification(int p_what) { VisualServer::get_singleton()->canvas_item_set_distance_field_mode(get_canvas_item(),font.is_valid() && font->is_distance_field_hint()); int font_h = font->get_height(); - int line_from=(int)get_val(); // + p_exposed.pos.y / font_h; int lines_visible = size.y/font_h; - int line_to=(int)get_val() + lines_visible; //p_exposed.pos.y+p_exposed.size.height / font_h; int space_w=font->get_char_size(' ').width; - int lines_total = get_max(); int chars_total=0; int vbegin=0,vsep=0; - - if (lines_total && lines_total < lines_visible) { + if (lines_visible > line_count) { + lines_visible = line_count; + + } + + if (max_lines_visible >= 0 && lines_visible > max_lines_visible) { + lines_visible = max_lines_visible; + + } + + if (lines_visible > 0) { switch(valign) { case VALIGN_TOP: { - //nothing } break; case VALIGN_CENTER: { - - vbegin=(lines_visible-lines_total) * font_h / 2; + vbegin=(size.y - lines_visible * font_h) / 2; vsep=0; + } break; case VALIGN_BOTTOM: { - vbegin=(lines_visible-lines_total) * font_h; + vbegin=size.y - lines_visible * font_h; vsep=0; } break; case VALIGN_FILL: { vbegin=0; - if (lines_total>1) { - vsep=(lines_visible-lines_total) * font_h / (lines_total-1); + if (lines_visible>1) { + vsep=(size.y - lines_visible * font_h) / (lines_visible - 1); } else { vsep=0; } @@ -130,20 +135,21 @@ void Label::_notification(int p_what) { } break; } } - - + + WordCache *wc = word_cache; if (!wc) return; - + int c = 0; int line=0; + int line_to=lines_skipped + (lines_visible>0?lines_visible:1); while(wc) { /* handle lines not meant to be drawn quickly */ - if (line>line_to) + if (line>=line_to) break; - if (line<line_from) { - + if (line<lines_skipped) { + while (wc && wc->char_pos>=0) wc=wc->next; if (wc) @@ -151,36 +157,36 @@ void Label::_notification(int p_what) { line++; continue; } - + /* handle lines normally */ - + if (wc->char_pos<0) { //empty line wc=wc->next; line++; continue; } - + WordCache *from=wc; WordCache *to=wc; - + int taken=0; int spaces=0; while(to && to->char_pos>=0) { - + taken+=to->pixel_width; if (to!=from && to->space_count) { spaces+=to->space_count; } to=to->next; } - + bool can_fill = to && to->char_pos==WordCache::CHAR_WRAPLINE; float x_ofs=0; - + switch (align) { - + case ALIGN_FILL: case ALIGN_LEFT: { @@ -198,16 +204,16 @@ void Label::_notification(int p_what) { } break; } - - int y_ofs=(line-(int)get_val())*font_h + font->get_ascent(); + + int y_ofs=(line-lines_skipped)*font_h + font->get_ascent(); y_ofs+=vbegin + line*vsep; - + while(from!=to) { - + // draw a word int pos = from->char_pos; if (from->char_pos<0) { - + ERR_PRINT("BUG"); return; } @@ -221,15 +227,15 @@ void Label::_notification(int p_what) { } - - - + + + if (font_color_shadow.a>0) { - + int chars_total_shadow = chars_total; //save chars drawn float x_ofs_shadow=x_ofs; for (int i=0;i<from->word_len;i++) { - + if (visible_chars < 0 || chars_total_shadow<visible_chars) { CharType c = text[i+pos]; CharType n = text[i+pos+1]; @@ -249,7 +255,7 @@ void Label::_notification(int p_what) { } } - + } for (int i=0;i<from->word_len;i++) { @@ -268,73 +274,73 @@ void Label::_notification(int p_what) { } from=from->next; } - + wc=to?to->next:0; line++; - - } + + } } - + if (p_what==NOTIFICATION_THEME_CHANGED) { word_cache_dirty=true; update(); } if (p_what==NOTIFICATION_RESIZED) { - + word_cache_dirty=true; } - + } Size2 Label::get_minimum_size() const { - + if (autowrap) return Size2(1,1); else { - + // don't want to mutable everything - if(word_cache_dirty) + if(word_cache_dirty) const_cast<Label*>(this)->regenerate_word_cache(); - + Size2 ms=minsize; if (clip) ms.width=1; return ms; - } + } } int Label::get_longest_line_width() const { - + Ref<Font> font = get_font("font"); int max_line_width=0; int line_width=0; - - for (int i=0;i<text.size()+1;i++) { - - CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works + + for (int i=0;i<text.size();i++) { + + CharType current=text[i]; if (uppercase) current=String::char_uppercase(current); if (current<32) { - + if (current=='\n') { - + if (line_width>max_line_width) max_line_width=line_width; line_width=0; } } else { - + int char_width=font->get_char_size(current).width; - line_width+=char_width; + line_width+=char_width; } - + } if (line_width>max_line_width) max_line_width=line_width; - + return max_line_width; } @@ -349,15 +355,15 @@ int Label::get_line_count() const { } void Label::regenerate_word_cache() { - + while (word_cache) { - + WordCache *current=word_cache; word_cache=current->next; memdelete( current ); } - - + + int width=autowrap?get_size().width:get_longest_line_width(); Ref<Font> font = get_font("font"); @@ -368,11 +374,11 @@ void Label::regenerate_word_cache() { int space_width=font->get_char_size(' ').width; line_count=1; total_char_cache=0; - + WordCache *last=NULL; - + for (int i=0;i<text.size()+1;i++) { - + CharType current=i<text.length()?text[i]:' '; //always a space at the end, so the algo works if (uppercase) @@ -429,12 +435,12 @@ void Label::regenerate_word_cache() { if (current_word_size==0) { word_pos=i; } - + char_width=font->get_char_size(current).width; current_word_size+=char_width; line_width+=char_width; total_char_cache++; - + } if ((autowrap && (line_width >= width) && ((last && last->char_pos >= 0) || separatable)) || insert_newline) { @@ -474,29 +480,22 @@ void Label::regenerate_word_cache() { space_count=0; } - + } - - //total_char_cache -= line_count + 1; // do not count new lines (including the first one) - + if (!autowrap) { - minsize.width=width; - minsize.height=font->get_height()*line_count; - set_page( line_count ); - - } else { - - set_page( get_size().height / font->get_height() ); + if (max_lines_visible > 0 && line_count > max_lines_visible) { + minsize.height=font->get_height()*max_lines_visible; + } else { + minsize.height=font->get_height()*line_count; + } } - - set_max(line_count); - + word_cache_dirty=false; } - void Label::set_align(Align p_align) { ERR_FAIL_INDEX(p_align,4); @@ -505,7 +504,7 @@ void Label::set_align(Align p_align) { } Label::Align Label::get_align() const{ - + return align; } @@ -522,24 +521,23 @@ Label::VAlign Label::get_valign() const{ } void Label::set_text(const String& p_string) { - + String str = XL_MESSAGE(p_string); if (text==str) return; - + text=str; word_cache_dirty=true; + if (percent_visible<1) + visible_chars=get_total_character_count()*percent_visible; update(); - if (!autowrap) - minimum_size_changed(); - + minimum_size_changed(); + } void Label::set_clip_text(bool p_clip) { - if (clip==p_clip) - return; clip=p_clip; update(); minimum_size_changed(); @@ -551,23 +549,39 @@ bool Label::is_clipping_text() const { } String Label::get_text() const { - + return text; } void Label::set_visible_characters(int p_amount) { visible_chars=p_amount; + if (get_total_character_count() > 0) { + percent_visible=(float)p_amount/(float)total_char_cache; + } update(); } +int Label::get_visible_characters() const { + + return visible_chars; +} + void Label::set_percent_visible(float p_percent) { - if (p_percent<0) - set_visible_characters(-1); - else - set_visible_characters(get_total_character_count()*p_percent); - percent_visible=p_percent; + if (p_percent<0 || p_percent>=1) { + + visible_chars=-1; + percent_visible=1; + + } else { + + visible_chars=get_total_character_count()*p_percent; + percent_visible=p_percent; + + } + update(); + } float Label::get_percent_visible() const{ @@ -575,6 +589,27 @@ float Label::get_percent_visible() const{ return percent_visible; } +void Label::set_lines_skipped(int p_lines) { + + lines_skipped=p_lines; + update(); +} + +int Label::get_lines_skipped() const{ + + return lines_skipped; +} + +void Label::set_max_lines_visible(int p_lines) { + + max_lines_visible=p_lines; + update(); +} + +int Label::get_max_lines_visible() const{ + + return max_lines_visible; +} int Label::get_total_character_count() const { @@ -585,7 +620,7 @@ int Label::get_total_character_count() const { } void Label::_bind_methods() { - + ObjectTypeDB::bind_method(_MD("set_align","align"),&Label::set_align); ObjectTypeDB::bind_method(_MD("get_align"),&Label::get_align); ObjectTypeDB::bind_method(_MD("set_valign","valign"),&Label::set_valign); @@ -594,14 +629,21 @@ void Label::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_text"),&Label::get_text); ObjectTypeDB::bind_method(_MD("set_autowrap","enable"),&Label::set_autowrap); ObjectTypeDB::bind_method(_MD("has_autowrap"),&Label::has_autowrap); + ObjectTypeDB::bind_method(_MD("set_clip_text","enable"),&Label::set_clip_text); + ObjectTypeDB::bind_method(_MD("is_clipping_text"),&Label::is_clipping_text); ObjectTypeDB::bind_method(_MD("set_uppercase","enable"),&Label::set_uppercase); ObjectTypeDB::bind_method(_MD("is_uppercase"),&Label::is_uppercase); ObjectTypeDB::bind_method(_MD("get_line_height"),&Label::get_line_height); ObjectTypeDB::bind_method(_MD("get_line_count"),&Label::get_line_count); ObjectTypeDB::bind_method(_MD("get_total_character_count"),&Label::get_total_character_count); - ObjectTypeDB::bind_method(_MD("set_visible_characters"),&Label::set_visible_characters); + ObjectTypeDB::bind_method(_MD("set_visible_characters","amount"),&Label::set_visible_characters); + ObjectTypeDB::bind_method(_MD("get_visible_characters"),&Label::get_visible_characters); ObjectTypeDB::bind_method(_MD("set_percent_visible","percent_visible"),&Label::set_percent_visible); ObjectTypeDB::bind_method(_MD("get_percent_visible"),&Label::get_percent_visible); + ObjectTypeDB::bind_method(_MD("set_lines_skipped","lines_skipped"),&Label::set_lines_skipped); + ObjectTypeDB::bind_method(_MD("get_lines_skipped"),&Label::get_lines_skipped); + ObjectTypeDB::bind_method(_MD("set_max_lines_visible","lines_visible"),&Label::set_max_lines_visible); + ObjectTypeDB::bind_method(_MD("get_max_lines_visible"),&Label::get_max_lines_visible); BIND_CONSTANT( ALIGN_LEFT ); BIND_CONSTANT( ALIGN_CENTER ); @@ -617,18 +659,21 @@ void Label::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") ); ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") ); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "clip_text"),_SCS("set_clip_text"),_SCS("is_clipping_text") ); ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") ); ADD_PROPERTY( PropertyInfo( Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_percent_visible"),_SCS("get_percent_visible") ); + ADD_PROPERTY( PropertyInfo( Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE,"0,999,1"),_SCS("set_lines_skipped"),_SCS("get_lines_skipped") ); + ADD_PROPERTY( PropertyInfo( Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE,"-1,999,1"),_SCS("set_max_lines_visible"),_SCS("get_max_lines_visible") ); } Label::Label(const String &p_text) { - + align=ALIGN_LEFT; valign=VALIGN_TOP; text=""; word_cache=NULL; - word_cache_dirty=true; + word_cache_dirty=true; autowrap=false; line_count=0; set_v_size_flags(0); @@ -636,20 +681,22 @@ Label::Label(const String &p_text) { set_ignore_mouse(true); total_char_cache=0; visible_chars=-1; - percent_visible=-1; + percent_visible=1; + lines_skipped=0; + max_lines_visible=-1; set_text(p_text); uppercase=false; } Label::~Label() { - + while (word_cache) { - + WordCache *current=word_cache; word_cache=current->next; memdelete( current ); - } + } } diff --git a/scene/gui/label.h b/scene/gui/label.h index 81e3ab5676..4ea9f5d377 100644 --- a/scene/gui/label.h +++ b/scene/gui/label.h @@ -29,17 +29,17 @@ #ifndef LABEL_H #define LABEL_H -#include "scene/gui/range.h" +#include "scene/gui/control.h" /** @author Juan Linietsky <reduzio@gmail.com> */ -class Label : public Range { - - OBJ_TYPE( Label, Range ); -public: - +class Label : public Control { + + OBJ_TYPE( Label, Control ); +public: + enum Align { - + ALIGN_LEFT, ALIGN_CENTER, ALIGN_RIGHT, @@ -63,11 +63,11 @@ private: Size2 minsize; int line_count; bool uppercase; - + int get_longest_line_width() const; - + struct WordCache { - + enum { CHAR_NEWLINE=-1, CHAR_WRAPLINE=-2 @@ -78,23 +78,25 @@ private: int space_count; WordCache *next; WordCache() { char_pos=0; word_len=0; pixel_width=0; next=0; space_count=0;} - }; - + }; + bool word_cache_dirty; void regenerate_word_cache(); float percent_visible; - + WordCache *word_cache; int total_char_cache; int visible_chars; -protected: + int lines_skipped; + int max_lines_visible; +protected: void _notification(int p_what); static void _bind_methods(); // bind helpers public: - + virtual Size2 get_minimum_size() const; void set_align(Align p_align); @@ -105,7 +107,7 @@ public: void set_text(const String& p_string); String get_text() const; - + void set_autowrap(bool p_autowrap); bool has_autowrap() const; @@ -113,6 +115,7 @@ public: bool is_uppercase() const; void set_visible_characters(int p_amount); + int get_visible_characters() const; int get_total_character_count() const; void set_clip_text(bool p_clip); @@ -121,6 +124,11 @@ public: void set_percent_visible(float p_percent); float get_percent_visible() const; + void set_lines_skipped(int p_lines); + int get_lines_skipped() const; + + void set_max_lines_visible(int p_lines); + int get_max_lines_visible() const; int get_line_height() const; int get_line_count() const; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1759f3eb04..b5fdde30cd 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -94,9 +94,9 @@ void TextEdit::Text::set_tab_size(int p_tab_size) { void TextEdit::Text::_update_line_cache(int p_line) const { - int w =0; - int tab_w=font->get_char_size(' ').width; - + int w = 0; + int tab_w=font->get_char_size(' ').width*tab_size; + int len = text[p_line].data.length(); const CharType *str = text[p_line].data.c_str(); @@ -292,7 +292,10 @@ void TextEdit::_update_scrollbars() { int vscroll_pixels = v_scroll->get_combined_minimum_size().width; int visible_width = size.width - cache.style_normal->get_minimum_size().width; - int total_width = text.get_max_width(); + int total_width = text.get_max_width() + vmin.x; + + if (line_numbers) + total_width += cache.line_number_w; bool use_hscroll=true; bool use_vscroll=true; @@ -322,7 +325,6 @@ void TextEdit::_update_scrollbars() { v_scroll->show(); v_scroll->set_max(total_rows); v_scroll->set_page(visible_rows); - v_scroll->set_val(cursor.line_ofs); } else { @@ -336,6 +338,7 @@ void TextEdit::_update_scrollbars() { h_scroll->set_max(total_width); h_scroll->set_page(visible_width); h_scroll->set_val(cursor.x_ofs); + } else { h_scroll->hide(); diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index c0b971cb33..f50552b32c 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -28,6 +28,88 @@ /*************************************************************************/ #include "video_player.h" + + +int VideoPlayer::InternalStream::get_channel_count() const { + + return player->sp_get_channel_count(); +} +void VideoPlayer::InternalStream::set_mix_rate(int p_rate){ + + return player->sp_set_mix_rate(p_rate); +} +bool VideoPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){ + + return player->sp_mix(p_buffer,p_frames); +} +void VideoPlayer::InternalStream::update(){ + + player->sp_update(); +} + + +int VideoPlayer::sp_get_channel_count() const { + + return playback->get_channels(); +} + +void VideoPlayer::sp_set_mix_rate(int p_rate){ + + server_mix_rate=p_rate; +} + +bool VideoPlayer::sp_mix(int32_t *p_buffer,int p_frames) { + + if (resampler.is_ready()) { + return resampler.mix(p_buffer,p_frames); + } + + return false; +} + +void VideoPlayer::sp_update() { +#if 0 + _THREAD_SAFE_METHOD_ + //update is unused + if (!paused && playback.is_valid()) { + + if (!playback->is_playing()) { + //stream depleted data, but there's still audio in the ringbuffer + //check that all this audio has been flushed before stopping the stream + int to_mix = resampler.get_total() - resampler.get_todo(); + if (to_mix==0) { + stop(); + return; + } + + return; + } + + int todo =resampler.get_todo(); + int wrote = playback->mix(resampler.get_write_buffer(),todo); + resampler.write(wrote); + } +#endif +} + +int VideoPlayer::_audio_mix_callback(void* p_udata,const int16_t *p_data,int p_frames) { + + VideoPlayer *vp=(VideoPlayer*)p_udata; + + int todo=MIN(vp->resampler.get_todo(),p_frames); + + int16_t *wb = vp->resampler.get_write_buffer(); + int c = vp->resampler.get_channel_count(); + + for(int i=0;i<todo*c;i++) { + wb[i]=p_data[i]; + } + vp->resampler.write(todo); + return todo; +} + + + void VideoPlayer::_notification(int p_notification) { switch (p_notification) { @@ -45,16 +127,25 @@ void VideoPlayer::_notification(int p_notification) { return; if (paused) return; - if (!stream->is_playing()) + if (!playback->is_playing()) return; - stream->update(get_tree()->get_idle_process_time()); - int prev_width = texture->get_width(); + double audio_time = AudioServer::get_singleton()->get_mix_time(); + + double delta = last_audio_time==0?0:audio_time-last_audio_time; + last_audio_time=audio_time; + if (delta==0) + return; + + + playback->update(delta); + + /*int prev_width = texture->get_width(); stream->pop_frame(texture); if (prev_width == 0) { update(); minimum_size_changed(); - }; + };*/ } break; @@ -75,6 +166,9 @@ void VideoPlayer::_notification(int p_notification) { }; + + + Size2 VideoPlayer::get_minimum_size() const { if (!expand && !texture.is_null()) @@ -100,15 +194,33 @@ void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) { stop(); - texture = Ref<ImageTexture>(memnew(ImageTexture)); - stream=p_stream; - if (!stream.is_null()) { - - stream->set_loop(loops); - stream->set_paused(paused); + if (stream.is_valid()) { + stream->set_audio_track(audio_track); + playback=stream->instance_playback(); + } else { + playback=Ref<VideoStreamPlayback>(); + } + + if (!playback.is_null()) { + playback->set_loop(loops); + playback->set_paused(paused); + texture=playback->get_texture(); + + AudioServer::get_singleton()->lock(); + resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,0); + AudioServer::get_singleton()->unlock(); + playback->set_mix_callback(_audio_mix_callback,this); + + } else { + texture.unref(); + AudioServer::get_singleton()->lock(); + resampler.clear(); + AudioServer::get_singleton()->unlock(); } + update(); + }; Ref<VideoStream> VideoPlayer::get_stream() const { @@ -119,36 +231,41 @@ Ref<VideoStream> VideoPlayer::get_stream() const { void VideoPlayer::play() { ERR_FAIL_COND(!is_inside_tree()); - if (stream.is_null()) + if (playback.is_null()) return; - stream->play(); + playback->stop(); + playback->play(); set_process(true); + AudioServer::get_singleton()->stream_set_active(stream_rid,true); + AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); + last_audio_time=0; }; void VideoPlayer::stop() { if (!is_inside_tree()) return; - if (stream.is_null()) + if (playback.is_null()) return; - stream->stop(); + playback->stop(); set_process(false); + last_audio_time=0; }; bool VideoPlayer::is_playing() const { - if (stream.is_null()) + if (playback.is_null()) return false; - return stream->is_playing(); + return playback->is_playing(); }; void VideoPlayer::set_paused(bool p_paused) { paused=p_paused; - if (stream.is_valid()) { - stream->set_paused(p_paused); + if (playback.is_valid()) { + playback->set_paused(p_paused); set_process(!p_paused); }; }; @@ -156,7 +273,27 @@ void VideoPlayer::set_paused(bool p_paused) { bool VideoPlayer::is_paused() const { return paused; -}; +} + +void VideoPlayer::set_buffering_msec(int p_msec) { + + buffering_ms=p_msec; +} + +int VideoPlayer::get_buffering_msec() const{ + + return buffering_ms; +} + +void VideoPlayer::set_audio_track(int p_track) { + audio_track=p_track; +} + +int VideoPlayer::get_audio_track() const { + + return audio_track; +} + void VideoPlayer::set_volume(float p_vol) { @@ -194,9 +331,9 @@ String VideoPlayer::get_stream_name() const { float VideoPlayer::get_stream_pos() const { - if (stream.is_null()) + if (playback.is_null()) return 0; - return stream->get_pos(); + return playback->get_pos(); }; @@ -229,6 +366,9 @@ void VideoPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&VideoPlayer::set_volume_db); ObjectTypeDB::bind_method(_MD("get_volume_db"),&VideoPlayer::get_volume_db); + ObjectTypeDB::bind_method(_MD("set_audio_track","track"),&VideoPlayer::set_audio_track); + ObjectTypeDB::bind_method(_MD("get_audio_track"),&VideoPlayer::get_audio_track); + ObjectTypeDB::bind_method(_MD("get_stream_name"),&VideoPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_stream_pos"),&VideoPlayer::get_stream_pos); @@ -239,13 +379,16 @@ void VideoPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_expand","enable"), &VideoPlayer::set_expand ); ObjectTypeDB::bind_method(_MD("has_expand"), &VideoPlayer::has_expand ); + ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&VideoPlayer::set_buffering_msec); + ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&VideoPlayer::get_buffering_msec); ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"VideoStream"), _SCS("set_stream"), _SCS("get_stream") ); // ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") ); ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") ); + ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/audio_track",PROPERTY_HINT_RANGE,"0,128,1"), _SCS("set_audio_track"), _SCS("get_audio_track") ); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") ); } @@ -257,6 +400,16 @@ VideoPlayer::VideoPlayer() { autoplay = false; expand = true; loops = false; + + audio_track=0; + + buffering_ms=500; + server_mix_rate=44100; + + internal_stream.player=this; + stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream); + last_audio_time=0; + }; VideoPlayer::~VideoPlayer() { diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h index 2b850ca509..c485e3d6b6 100644 --- a/scene/gui/video_player.h +++ b/scene/gui/video_player.h @@ -31,22 +31,50 @@ #include "scene/resources/video_stream.h" #include "scene/gui/control.h" +#include "servers/audio/audio_rb_resampler.h" class VideoPlayer : public Control { OBJ_TYPE(VideoPlayer,Control); + struct InternalStream : public AudioServer::AudioStream { + VideoPlayer *player; + virtual int get_channel_count() const; + virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate + virtual bool mix(int32_t *p_buffer,int p_frames); + virtual void update(); + }; + + + InternalStream internal_stream; + Ref<VideoStreamPlayback> playback; Ref<VideoStream> stream; + + int sp_get_channel_count() const; + void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate + bool sp_mix(int32_t *p_buffer,int p_frames); + void sp_update(); + + RID stream_rid; Ref<ImageTexture> texture; Image last_frame; + AudioRBResampler resampler; + bool paused; bool autoplay; float volume; + double last_audio_time; bool expand; bool loops; + int buffering_ms; + int server_mix_rate; + int audio_track; + + static int _audio_mix_callback(void* p_udata,const int16_t *p_data,int p_frames); + protected: @@ -82,6 +110,12 @@ public: void set_autoplay(bool p_vol); bool has_autoplay() const; + void set_audio_track(int p_track); + int get_audio_track() const; + + void set_buffering_msec(int p_msec); + int get_buffering_msec() const; + VideoPlayer(); ~VideoPlayer(); }; diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp index 090348c933..00b800b28b 100644 --- a/scene/io/resource_format_wav.cpp +++ b/scene/io/resource_format_wav.cpp @@ -252,6 +252,7 @@ RES ResourceFormatLoaderWAV::load(const String &p_path, const String& p_original if (r_error) *r_error=OK; + return sample; } diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 45e3d92ece..adf053f5c9 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -42,6 +42,8 @@ #include "io/resource_loader.h" #include "viewport.h" #include "scene/resources/packed_scene.h" +#include "scene/resources/material.h" +#include "scene/resources/mesh.h" void SceneTree::tree_changed() { @@ -470,7 +472,6 @@ void SceneTree::init() { input_handled=false; - editor_hint=false; pause=false; root->_set_tree(this); @@ -624,6 +625,175 @@ bool SceneTree::is_editor_hint() const { return editor_hint; } +void SceneTree::set_debug_collisions_hint(bool p_enabled) { + + debug_collisions_hint=p_enabled; +} + +bool SceneTree::is_debugging_collisions_hint() const { + + return debug_collisions_hint; +} + +void SceneTree::set_debug_navigation_hint(bool p_enabled) { + + debug_navigation_hint=p_enabled; +} + +bool SceneTree::is_debugging_navigation_hint() const { + + return debug_navigation_hint; +} + +void SceneTree::set_debug_collisions_color(const Color& p_color) { + + debug_collisions_color=p_color; +} + +Color SceneTree::get_debug_collisions_color() const { + + return debug_collisions_color; +} + +void SceneTree::set_debug_collision_contact_color(const Color& p_color) { + + debug_collision_contact_color=p_color; +} + +Color SceneTree::get_debug_collision_contact_color() const { + + return debug_collision_contact_color; +} + +void SceneTree::set_debug_navigation_color(const Color& p_color) { + + debug_navigation_color=p_color; +} + +Color SceneTree::get_debug_navigation_color() const { + + return debug_navigation_color; +} + +void SceneTree::set_debug_navigation_disabled_color(const Color& p_color) { + + debug_navigation_disabled_color=p_color; +} + +Color SceneTree::get_debug_navigation_disabled_color() const { + + return debug_navigation_disabled_color; +} + +Ref<Material> SceneTree::get_debug_navigation_material() { + + if (navigation_material.is_valid()) + return navigation_material; + + Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial )); + line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_navigation_color()); + + navigation_material=line_material; + + return navigation_material; + +} + +Ref<Material> SceneTree::get_debug_navigation_disabled_material(){ + + if (navigation_disabled_material.is_valid()) + return navigation_disabled_material; + + Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial )); + line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_navigation_disabled_color()); + + navigation_disabled_material=line_material; + + return navigation_disabled_material; + +} +Ref<Material> SceneTree::get_debug_collision_material() { + + if (collision_material.is_valid()) + return collision_material; + + + Ref<FixedMaterial> line_material = Ref<FixedMaterial>( memnew( FixedMaterial )); + line_material->set_flag(Material::FLAG_UNSHADED, true); + line_material->set_line_width(3.0); + line_material->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA, true); + line_material->set_fixed_flag(FixedMaterial::FLAG_USE_COLOR_ARRAY, true); + line_material->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_collisions_color()); + + collision_material=line_material; + + return collision_material; +} + +Ref<Mesh> SceneTree::get_debug_contact_mesh() { + + if (debug_contact_mesh.is_valid()) + return debug_contact_mesh; + + debug_contact_mesh = Ref<Mesh>( memnew( Mesh ) ); + + Ref<FixedMaterial> mat = memnew( FixedMaterial ); + mat->set_flag(Material::FLAG_UNSHADED,true); + mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); + mat->set_fixed_flag(FixedMaterial::FLAG_USE_ALPHA,true); + mat->set_parameter(FixedMaterial::PARAM_DIFFUSE,get_debug_collision_contact_color()); + + Vector3 diamond[6]={ + Vector3(-1, 0, 0), + Vector3( 1, 0, 0), + Vector3( 0, -1, 0), + Vector3( 0, 1, 0), + Vector3( 0, 0, -1), + Vector3( 0, 0, 1) + }; + + int diamond_faces[8*3]={ + 0,2,4, + 0,3,4, + 1,2,4, + 1,3,4, + 0,2,5, + 0,3,5, + 1,2,5, + 1,3,5, + }; + + DVector<int> indices; + for(int i=0;i<8*3;i++) + indices.push_back(diamond_faces[i]); + + DVector<Vector3> vertices; + for(int i=0;i<6;i++) + vertices.push_back(diamond[i]*0.1); + + Array arr; + arr.resize(Mesh::ARRAY_MAX); + arr[Mesh::ARRAY_VERTEX]=vertices; + arr[Mesh::ARRAY_INDEX]=indices; + + + debug_contact_mesh->add_surface(Mesh::PRIMITIVE_TRIANGLES,arr); + debug_contact_mesh->surface_set_material(0,mat); + + return debug_contact_mesh; + +} + + + void SceneTree::set_pause(bool p_enabled) { if (p_enabled==pause) @@ -1424,6 +1594,11 @@ void SceneTree::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_editor_hint","enable"),&SceneTree::set_editor_hint); ObjectTypeDB::bind_method(_MD("is_editor_hint"),&SceneTree::is_editor_hint); + ObjectTypeDB::bind_method(_MD("set_debug_collisions_hint","enable"),&SceneTree::set_debug_collisions_hint); + ObjectTypeDB::bind_method(_MD("is_debugging_collisions_hint"),&SceneTree::is_debugging_collisions_hint); + ObjectTypeDB::bind_method(_MD("set_debug_navigation_hint","enable"),&SceneTree::set_debug_navigation_hint); + ObjectTypeDB::bind_method(_MD("is_debugging_navigation_hint"),&SceneTree::is_debugging_navigation_hint); + #ifdef TOOLS_ENABLED ObjectTypeDB::bind_method(_MD("set_edited_scene_root","scene"),&SceneTree::set_edited_scene_root); ObjectTypeDB::bind_method(_MD("get_edited_scene_root"),&SceneTree::get_edited_scene_root); @@ -1490,10 +1665,23 @@ void SceneTree::_bind_methods() { } +SceneTree *SceneTree::singleton=NULL; + SceneTree::SceneTree() { + singleton=this; _quit=false; initialized=false; + editor_hint=false; + debug_collisions_hint=false; + debug_navigation_hint=false; + debug_collisions_color=GLOBAL_DEF("debug/collision_shape_color",Color(0.0,0.6,0.7,0.5)); + debug_collision_contact_color=GLOBAL_DEF("debug/collision_contact_color",Color(1.0,0.2,0.1,0.8)); + debug_navigation_color=GLOBAL_DEF("debug/navigation_geometry_color",Color(0.1,1.0,0.7,0.4)); + debug_navigation_disabled_color=GLOBAL_DEF("debug/navigation_disabled_geometry_color",Color(1.0,0.7,0.1,0.4)); + collision_debug_contacts=GLOBAL_DEF("debug/collision_max_contacts_displayed",10000); + + tree_version=1; fixed_process_time=1; idle_process_time=1; diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 1f09d9c546..8d9021d24e 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -45,6 +45,8 @@ class SceneTree; class PackedScene; class Node; class Viewport; +class Material; +class Mesh; class SceneTree : public MainLoop { @@ -87,6 +89,8 @@ private: uint32_t last_id; bool editor_hint; + bool debug_collisions_hint; + bool debug_navigation_hint; bool pause; int root_lock; @@ -138,9 +142,20 @@ private: Node *current_scene; + Color debug_collisions_color; + Color debug_collision_contact_color; + Color debug_navigation_color; + Color debug_navigation_disabled_color; + Ref<Mesh> debug_contact_mesh; + Ref<Material> navigation_material; + Ref<Material> navigation_disabled_material; + Ref<Material> collision_material; + int collision_debug_contacts; + void _change_scene(Node* p_to); //void _call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,const Variant& p_arg1,const Variant& p_arg2); + static SceneTree *singleton; friend class Node; void tree_changed(); @@ -270,6 +285,32 @@ public: void set_camera(const RID& p_camera); RID get_camera() const; + void set_debug_collisions_hint(bool p_enabled); + bool is_debugging_collisions_hint() const; + + void set_debug_navigation_hint(bool p_enabled); + bool is_debugging_navigation_hint() const; + + void set_debug_collisions_color(const Color& p_color); + Color get_debug_collisions_color() const; + + void set_debug_collision_contact_color(const Color& p_color); + Color get_debug_collision_contact_color() const; + + void set_debug_navigation_color(const Color& p_color); + Color get_debug_navigation_color() const; + + void set_debug_navigation_disabled_color(const Color& p_color); + Color get_debug_navigation_disabled_color() const; + + + Ref<Material> get_debug_navigation_material(); + Ref<Material> get_debug_navigation_disabled_material(); + Ref<Material> get_debug_collision_material(); + Ref<Mesh> get_debug_contact_mesh(); + + int get_collision_debug_contact_count() { return collision_debug_contacts; } + int64_t get_frame() const; int get_node_count() const; @@ -297,6 +338,7 @@ public: //used by Main::start, don't use otherwise void add_current_scene(Node * p_current); + static SceneTree* get_singleton() { return singleton; } SceneTree(); diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index 3a80382a40..1bd22a9db1 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -182,11 +182,14 @@ void Timer::_bind_methods() { ADD_SIGNAL( MethodInfo("timeout") ); - ADD_PROPERTY(PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_timer_process_mode"), _SCS("get_timer_process_mode")); + ADD_PROPERTY( PropertyInfo(Variant::INT, "process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_timer_process_mode"), _SCS("get_timer_process_mode") ); ADD_PROPERTY( PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.01,4096,0.01" ), _SCS("set_wait_time"), _SCS("get_wait_time") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "one_shot" ), _SCS("set_one_shot"), _SCS("is_one_shot") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "autostart" ), _SCS("set_autostart"), _SCS("has_autostart") ); + BIND_CONSTANT( TIMER_PROCESS_FIXED ); + BIND_CONSTANT( TIMER_PROCESS_IDLE ); + } Timer::Timer() { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 3bb64e54c6..d19b5767c2 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -37,6 +37,7 @@ #include "servers/spatial_sound_2d_server.h" #include "scene/gui/control.h" #include "scene/3d/camera.h" +#include "scene/resources/mesh.h" #include "scene/3d/spatial_indexer.h" #include "scene/3d/collision_object.h" @@ -319,6 +320,23 @@ void Viewport::_notification(int p_what) { } add_to_group("_viewports"); + if (get_tree()->is_debugging_collisions_hint()) { + //2D + Physics2DServer::get_singleton()->space_set_debug_contacts(find_world_2d()->get_space(),get_tree()->get_collision_debug_contact_count()); + contact_2d_debug=VisualServer::get_singleton()->canvas_item_create(); + VisualServer::get_singleton()->canvas_item_set_parent(contact_2d_debug,find_world_2d()->get_canvas()); + //3D + PhysicsServer::get_singleton()->space_set_debug_contacts(find_world()->get_space(),get_tree()->get_collision_debug_contact_count()); + contact_3d_debug_multimesh=VisualServer::get_singleton()->multimesh_create(); + VisualServer::get_singleton()->multimesh_set_instance_count(contact_3d_debug_multimesh,get_tree()->get_collision_debug_contact_count()); + VisualServer::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh,0); + VisualServer::get_singleton()->multimesh_set_mesh(contact_3d_debug_multimesh,get_tree()->get_debug_contact_mesh()->get_rid()); + contact_3d_debug_instance=VisualServer::get_singleton()->instance_create(); + VisualServer::get_singleton()->instance_set_base(contact_3d_debug_instance,contact_3d_debug_multimesh); + VisualServer::get_singleton()->instance_set_scenario(contact_3d_debug_instance,find_world()->get_scenario()); + VisualServer::get_singleton()->instance_geometry_set_flag(contact_3d_debug_instance,VS::INSTANCE_FLAG_VISIBLE_IN_ALL_ROOMS,true); + + } } break; case NOTIFICATION_READY: { @@ -351,11 +369,69 @@ void Viewport::_notification(int p_what) { VisualServer::get_singleton()->viewport_set_scenario(viewport,RID()); SpatialSoundServer::get_singleton()->listener_set_space(listener,RID()); VisualServer::get_singleton()->viewport_remove_canvas(viewport,current_canvas); + if (contact_2d_debug.is_valid()) { + VisualServer::get_singleton()->free(contact_2d_debug); + contact_2d_debug=RID(); + } + + if (contact_3d_debug_multimesh.is_valid()) { + VisualServer::get_singleton()->free(contact_3d_debug_multimesh); + VisualServer::get_singleton()->free(contact_3d_debug_instance); + contact_3d_debug_instance=RID(); + contact_3d_debug_multimesh=RID(); + } + remove_from_group("_viewports"); } break; case NOTIFICATION_FIXED_PROCESS: { + + if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) { + + VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug); + VisualServer::get_singleton()->canvas_item_raise(contact_2d_debug); + + Vector<Vector2> points = Physics2DServer::get_singleton()->space_get_contacts(find_world_2d()->get_space()); + int point_count = Physics2DServer::get_singleton()->space_get_contact_count(find_world_2d()->get_space()); + Color ccol = get_tree()->get_debug_collision_contact_color(); + + + for(int i=0;i<point_count;i++) { + + VisualServer::get_singleton()->canvas_item_add_rect(contact_2d_debug,Rect2(points[i]-Vector2(2,2),Vector2(5,5)),ccol); + } + } + + if (get_tree()->is_debugging_collisions_hint() && contact_3d_debug_multimesh.is_valid()) { + + + Vector<Vector3> points = PhysicsServer::get_singleton()->space_get_contacts(find_world()->get_space()); + int point_count = PhysicsServer::get_singleton()->space_get_contact_count(find_world()->get_space()); + + + VS::get_singleton()->multimesh_set_visible_instances(contact_3d_debug_multimesh,point_count); + + if (point_count>0) { + AABB aabb; + + Transform t; + for(int i=0;i<point_count;i++) { + + if (i==0) + aabb.pos=points[i]; + else + aabb.expand_to(points[i]); + t.origin=points[i]; + VisualServer::get_singleton()->multimesh_instance_set_transform(contact_3d_debug_multimesh,i,t); + } + aabb.grow(aabb.get_longest_axis_size()*0.01); + VisualServer::get_singleton()->multimesh_set_aabb(contact_3d_debug_multimesh,aabb); + } + } + + + if (physics_object_picking) { Vector2 last_pos(1e20,1e20); @@ -1449,6 +1525,8 @@ Viewport::Viewport() { unhandled_key_input_group = "_vp_unhandled_key_input"+id; + + } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index c3c339ac5d..843a1fd9b7 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -104,6 +104,11 @@ friend class RenderTargetTexture; Rect2 rect; Rect2 to_screen_rect; + RID contact_2d_debug; + RID contact_3d_debug_multimesh; + RID contact_3d_debug_instance; + + bool size_override; bool size_override_stretch; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index a53c69815f..851de4a89f 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -458,7 +458,6 @@ void register_scene_types() { /* disable types by default, only editors should enable them */ - ObjectTypeDB::set_type_enabled("CollisionShape",false); //ObjectTypeDB::set_type_enabled("BodyVolumeSphere",false); //ObjectTypeDB::set_type_enabled("BodyVolumeBox",false); //ObjectTypeDB::set_type_enabled("BodyVolumeCapsule",false); @@ -492,9 +491,12 @@ void register_scene_types() { ObjectTypeDB::register_type<OccluderPolygon2D>(); ObjectTypeDB::register_type<YSort>(); ObjectTypeDB::register_type<BackBufferCopy>(); - - ObjectTypeDB::set_type_enabled("CollisionShape2D",false); - ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false); + if (bool(GLOBAL_DEF("physics/remove_collision_helpers_at_runtime",false))) { + ObjectTypeDB::set_type_enabled("CollisionShape2D",false); + ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false); + ObjectTypeDB::set_type_enabled("CollisionShape",false); + ObjectTypeDB::set_type_enabled("CollisionPolygon",false); + } OS::get_singleton()->yield(); //may take time to init @@ -578,7 +580,8 @@ void register_scene_types() { ObjectTypeDB::register_type<Sample>(); ObjectTypeDB::register_type<SampleLibrary>(); ObjectTypeDB::register_virtual_type<AudioStream>(); - ObjectTypeDB::register_type<AudioStreamGibberish>(); + ObjectTypeDB::register_virtual_type<AudioStreamPlayback>(); +// ObjectTypeDB::register_type<AudioStreamGibberish>(); ObjectTypeDB::register_virtual_type<VideoStream>(); OS::get_singleton()->yield(); //may take time to init diff --git a/scene/resources/audio_stream.cpp b/scene/resources/audio_stream.cpp index 7694b8ef79..569ed8620d 100644 --- a/scene/resources/audio_stream.cpp +++ b/scene/resources/audio_stream.cpp @@ -28,76 +28,34 @@ /*************************************************************************/ #include "audio_stream.h" +////////////////////////////// -int AudioStream::InternalAudioStream::get_channel_count() const { +void AudioStreamPlayback::_bind_methods() { - return owner->get_channel_count(); + ObjectTypeDB::bind_method(_MD("play","from_pos_sec"),&AudioStreamPlayback::play,DEFVAL(0)); + ObjectTypeDB::bind_method(_MD("stop"),&AudioStreamPlayback::stop); + ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStreamPlayback::is_playing); -} - -void AudioStream::InternalAudioStream::set_mix_rate(int p_rate) { - - owner->_mix_rate=p_rate; -} - -bool AudioStream::InternalAudioStream::mix(int32_t *p_buffer,int p_frames) { - - return owner->mix(p_buffer,p_frames); -} - -bool AudioStream::InternalAudioStream::can_update_mt() const { + ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStreamPlayback::set_loop); + ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStreamPlayback::has_loop); - return owner->get_update_mode()==UPDATE_THREAD; -} + ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStreamPlayback::get_loop_count); -void AudioStream::InternalAudioStream::update() { + ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStreamPlayback::seek_pos); + ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStreamPlayback::get_pos); - owner->update(); -} + ObjectTypeDB::bind_method(_MD("get_length"),&AudioStreamPlayback::get_length); + ObjectTypeDB::bind_method(_MD("get_channels"),&AudioStreamPlayback::get_channels); + ObjectTypeDB::bind_method(_MD("get_mix_rate"),&AudioStreamPlayback::get_mix_rate); + ObjectTypeDB::bind_method(_MD("get_minimum_buffer_size"),&AudioStreamPlayback::get_minimum_buffer_size); -AudioServer::AudioStream *AudioStream::get_audio_stream() { - return internal_audio_stream; } void AudioStream::_bind_methods() { - ObjectTypeDB::bind_method(_MD("play"),&AudioStream::play); - ObjectTypeDB::bind_method(_MD("stop"),&AudioStream::stop); - ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStream::is_playing); - - ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStream::set_loop); - ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStream::has_loop); - - ObjectTypeDB::bind_method(_MD("get_stream_name"),&AudioStream::get_stream_name); - ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStream::get_loop_count); - - ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStream::seek_pos); - ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStream::get_pos); - - ObjectTypeDB::bind_method(_MD("get_length"),&AudioStream::get_length); - - ObjectTypeDB::bind_method(_MD("get_update_mode"),&AudioStream::get_update_mode); - - ObjectTypeDB::bind_method(_MD("update"),&AudioStream::update); - - BIND_CONSTANT( UPDATE_NONE ); - BIND_CONSTANT( UPDATE_IDLE ); - BIND_CONSTANT( UPDATE_THREAD ); } -AudioStream::AudioStream() { - - _mix_rate=44100; - internal_audio_stream = memnew( InternalAudioStream ); - internal_audio_stream->owner=this; -} - - -AudioStream::~AudioStream() { - - memdelete(internal_audio_stream); -} diff --git a/scene/resources/audio_stream.h b/scene/resources/audio_stream.h index df33b64a4b..b16e62b8c7 100644 --- a/scene/resources/audio_stream.h +++ b/scene/resources/audio_stream.h @@ -31,72 +31,53 @@ #include "resource.h" #include "servers/audio_server.h" -#include "scene/resources/audio_stream.h" - -class AudioStream : public Resource { - - OBJ_TYPE( AudioStream, Resource ); - OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged - - friend class InternalAudioStream; - - struct InternalAudioStream : public AudioServer::AudioStream { - - ::AudioStream *owner; - virtual int get_channel_count() const; - virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate - virtual bool mix(int32_t *p_buffer,int p_frames); - virtual bool can_update_mt() const; - virtual void update(); - }; +class AudioStreamPlayback : public Reference { - int _mix_rate; - InternalAudioStream *internal_audio_stream; + OBJ_TYPE( AudioStreamPlayback, Reference ); protected: - - _FORCE_INLINE_ int get_mix_rate() const { return _mix_rate; } - virtual int get_channel_count() const=0; - virtual bool mix(int32_t *p_buffer, int p_frames)=0; - static void _bind_methods(); public: - enum UpdateMode { - UPDATE_NONE, - UPDATE_IDLE, - UPDATE_THREAD - }; - AudioServer::AudioStream *get_audio_stream(); - - virtual void play()=0; + virtual void play(float p_from_pos=0)=0; virtual void stop()=0; virtual bool is_playing() const=0; - virtual void set_paused(bool p_paused)=0; - virtual bool is_paused(bool p_paused) const=0; - virtual void set_loop(bool p_enable)=0; virtual bool has_loop() const=0; - virtual float get_length() const=0; - - virtual String get_stream_name() const=0; + virtual void set_loop_restart_time(float p_time)=0; virtual int get_loop_count() const=0; virtual float get_pos() const=0; virtual void seek_pos(float p_time)=0; - virtual UpdateMode get_update_mode() const=0; - virtual void update()=0; + virtual int mix(int16_t* p_bufer,int p_frames)=0; + + virtual float get_length() const=0; + virtual String get_stream_name() const=0; + + virtual int get_channels() const=0; + virtual int get_mix_rate() const=0; + virtual int get_minimum_buffer_size() const=0; - AudioStream(); - ~AudioStream(); }; +class AudioStream : public Resource { + + OBJ_TYPE( AudioStream, Resource ); + OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged + +protected: + static void _bind_methods(); +public: + + virtual Ref<AudioStreamPlayback> instance_playback()=0; + + +}; -VARIANT_ENUM_CAST( AudioStream::UpdateMode ); #endif // AUDIO_STREAM_H diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp index 6317780bd3..edbca60bd3 100644 --- a/scene/resources/audio_stream_resampled.cpp +++ b/scene/resources/audio_stream_resampled.cpp @@ -28,6 +28,9 @@ /*************************************************************************/ #include "audio_stream_resampled.h" #include "globals.h" + + +#if 0 int AudioStreamResampled::get_channel_count() const { if (!rb) @@ -382,3 +385,4 @@ AudioStreamResampled::~AudioStreamResampled() { } +#endif diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h index 33cfb17e3f..570c311878 100644 --- a/scene/resources/audio_stream_resampled.h +++ b/scene/resources/audio_stream_resampled.h @@ -31,6 +31,7 @@ #include "scene/resources/audio_stream.h" +#if 0 class AudioStreamResampled : public AudioStream { OBJ_TYPE(AudioStreamResampled,AudioStream); @@ -160,5 +161,5 @@ public: AudioStreamResampled(); ~AudioStreamResampled(); }; - +#endif #endif // AUDIO_STREAM_RESAMPLED_H diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp index 22ee9f8c09..ba29a1b601 100644 --- a/scene/resources/box_shape.cpp +++ b/scene/resources/box_shape.cpp @@ -30,6 +30,25 @@ #include "servers/physics_server.h" +Vector<Vector3> BoxShape::_gen_debug_mesh_lines() { + + + Vector<Vector3> lines; + AABB aabb; + aabb.pos=-get_extents(); + aabb.size=aabb.pos*-2; + + for(int i=0;i<12;i++) { + Vector3 a,b; + aabb.get_edge(i,a,b); + lines.push_back(a); + lines.push_back(b); + } + + + return lines; +} + void BoxShape::_update_shape() { PhysicsServer::get_singleton()->shape_set_data(get_shape(),extents); diff --git a/scene/resources/box_shape.h b/scene/resources/box_shape.h index 18c5f5e5fb..9667515657 100644 --- a/scene/resources/box_shape.h +++ b/scene/resources/box_shape.h @@ -41,6 +41,7 @@ protected: static void _bind_methods(); virtual void _update_shape(); + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp index 2633b132cf..67ceed6be0 100644 --- a/scene/resources/capsule_shape.cpp +++ b/scene/resources/capsule_shape.cpp @@ -30,6 +30,46 @@ #include "servers/physics_server.h" +Vector<Vector3> CapsuleShape::_gen_debug_mesh_lines() { + + + float radius = get_radius(); + float height = get_height(); + + + Vector<Vector3> points; + + Vector3 d(0,0,height*0.5); + for(int i=0;i<360;i++) { + + float ra=Math::deg2rad(i); + float rb=Math::deg2rad(i+1); + Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*radius; + Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*radius; + + points.push_back(Vector3(a.x,a.y,0)+d); + points.push_back(Vector3(b.x,b.y,0)+d); + + points.push_back(Vector3(a.x,a.y,0)-d); + points.push_back(Vector3(b.x,b.y,0)-d); + + if (i%90==0) { + + points.push_back(Vector3(a.x,a.y,0)+d); + points.push_back(Vector3(a.x,a.y,0)-d); + } + + Vector3 dud = i<180?d:-d; + + points.push_back(Vector3(0,a.y,a.x)+dud); + points.push_back(Vector3(0,b.y,b.x)+dud); + points.push_back(Vector3(a.y,0,a.x)+dud); + points.push_back(Vector3(b.y,0,b.x)+dud); + + } + + return points; +} void CapsuleShape::_update_shape() { @@ -65,7 +105,6 @@ float CapsuleShape::get_height() const { return height; } - void CapsuleShape::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CapsuleShape::set_radius); diff --git a/scene/resources/capsule_shape.h b/scene/resources/capsule_shape.h index 43b8331949..e516d0e3c7 100644 --- a/scene/resources/capsule_shape.h +++ b/scene/resources/capsule_shape.h @@ -43,6 +43,7 @@ protected: virtual void _update_shape(); + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: void set_radius(float p_radius); @@ -50,6 +51,7 @@ public: void set_height(float p_height); float get_height() const; + CapsuleShape(); }; diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp index 135eb41d8f..923a509ad5 100644 --- a/scene/resources/capsule_shape_2d.cpp +++ b/scene/resources/capsule_shape_2d.cpp @@ -29,6 +29,7 @@ #include "capsule_shape_2d.h" #include "servers/physics_2d_server.h" +#include "servers/visual_server.h" void CapsuleShape2D::_update_shape() { @@ -60,6 +61,32 @@ real_t CapsuleShape2D::get_height() const { } +void CapsuleShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + Vector<Vector2> points; + for(int i=0;i<24;i++) { + Vector2 ofs = Vector2(0,(i>6 && i<=18) ? -get_height()*0.5 : get_height()*0.5); + + points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*get_radius() + ofs); + if (i==6 || i==18) + points.push_back(Vector2(Math::sin(i*Math_PI*2/24.0),Math::cos(i*Math_PI*2/24.0))*get_radius() - ofs); + } + + Vector<Color> col; + col.push_back(p_color); + VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col); + +} + +Rect2 CapsuleShape2D::get_rect() const { + + Vector2 he=Point2(get_radius(),get_radius()+get_height()*0.5); + Rect2 rect; + rect.pos=-he; + rect.size=he*2.0; + return rect; +} + void CapsuleShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CapsuleShape2D::set_radius); diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h index 4dd6348282..dc679966f9 100644 --- a/scene/resources/capsule_shape_2d.h +++ b/scene/resources/capsule_shape_2d.h @@ -49,6 +49,9 @@ public: void set_radius(real_t p_radius); real_t get_radius() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const ; + CapsuleShape2D(); }; diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index 4135bc7c3b..c77395612c 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -29,7 +29,7 @@ #include "circle_shape_2d.h" #include "servers/physics_2d_server.h" - +#include "servers/visual_server.h" void CircleShape2D::_update_shape() { Physics2DServer::get_singleton()->shape_set_data(get_rid(),radius); @@ -58,6 +58,27 @@ void CircleShape2D::_bind_methods() { } +Rect2 CircleShape2D::get_rect() const { + Rect2 rect; + rect.pos=-Point2(get_radius(),get_radius()); + rect.size=Point2(get_radius(),get_radius())*2.0; + return rect; +} + +void CircleShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + Vector<Vector2> points; + for(int i=0;i<24;i++) { + + points.push_back(Vector2(Math::cos(i*Math_PI*2/24.0),Math::sin(i*Math_PI*2/24.0))*get_radius()); + } + + Vector<Color> col; + col.push_back(p_color); + VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col); + +} + CircleShape2D::CircleShape2D() : Shape2D( Physics2DServer::get_singleton()->shape_create(Physics2DServer::SHAPE_CIRCLE)) { radius=10; diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h index d937af2979..a5902b189c 100644 --- a/scene/resources/circle_shape_2d.h +++ b/scene/resources/circle_shape_2d.h @@ -44,6 +44,10 @@ public: void set_radius(real_t p_radius); real_t get_radius() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const; + + CircleShape2D(); }; diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp index 55bd5de690..7aeac04a22 100644 --- a/scene/resources/concave_polygon_shape.cpp +++ b/scene/resources/concave_polygon_shape.cpp @@ -30,6 +30,40 @@ #include "servers/physics_server.h" +Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() { + + Set<DrawEdge> edges; + + DVector<Vector3> data=get_faces(); + int datalen=data.size(); + ERR_FAIL_COND_V( (datalen%3)!=0,Vector<Vector3>() ); + + DVector<Vector3>::Read r=data.read(); + + for(int i=0;i<datalen;i+=3) { + + for(int j=0;j<3;j++) { + + DrawEdge de(r[i+j],r[i+((j+1)%3)]); + edges.insert(de); + } + + } + + Vector<Vector3> points; + points.resize(edges.size()*2); + int idx=0; + for (Set<DrawEdge>::Element*E=edges.front();E;E=E->next()) { + + points[idx+0]=E->get().a; + points[idx+1]=E->get().b; + idx+=2; + } + + return points; + +} + bool ConcavePolygonShape::_set(const StringName& p_name, const Variant& p_value) { if (p_name=="data") diff --git a/scene/resources/concave_polygon_shape.h b/scene/resources/concave_polygon_shape.h index 7bd80eb9c0..fae98ee046 100644 --- a/scene/resources/concave_polygon_shape.h +++ b/scene/resources/concave_polygon_shape.h @@ -35,16 +35,36 @@ class ConcavePolygonShape : public Shape { OBJ_TYPE(ConcavePolygonShape,Shape); + struct DrawEdge { + + Vector3 a; + Vector3 b; + bool operator<(const DrawEdge& p_edge) const { + if (a==p_edge.a) + return b<p_edge.b; + else + return a<p_edge.a; + } + + DrawEdge(const Vector3& p_a=Vector3(),const Vector3& p_b=Vector3()) { + a=p_a; + b=p_b; + if (a<b) { + SWAP(a,b); + } + } + }; protected: + bool _set(const StringName& p_name, const Variant& p_value); bool _get(const StringName& p_name,Variant &r_ret) const; void _get_property_list( List<PropertyInfo> *p_list) const; static void _bind_methods(); virtual void _update_shape(); - + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: void set_faces(const DVector<Vector3>& p_faces); diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp index 0287d79dc6..923e2817ef 100644 --- a/scene/resources/concave_polygon_shape_2d.cpp +++ b/scene/resources/concave_polygon_shape_2d.cpp @@ -29,7 +29,7 @@ #include "concave_polygon_shape_2d.h" #include "servers/physics_2d_server.h" - +#include "servers/visual_server.h" void ConcavePolygonShape2D::set_segments(const DVector<Vector2>& p_segments) { @@ -41,6 +41,43 @@ DVector<Vector2> ConcavePolygonShape2D::get_segments() const { return Physics2DServer::get_singleton()->shape_get_data(get_rid()); } +void ConcavePolygonShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + + DVector<Vector2> s = get_segments(); + int len=s.size(); + if (len==0 || (len%2)==1) + return; + + DVector<Vector2>::Read r = s.read(); + for(int i=0;i<len;i+=2) { + VisualServer::get_singleton()->canvas_item_add_line(p_to_rid,r[i],r[i+1],p_color,2); + } + +} + +Rect2 ConcavePolygonShape2D::get_rect() const { + + + DVector<Vector2> s = get_segments(); + int len=s.size(); + if (len==0) + return Rect2(); + + Rect2 rect; + + DVector<Vector2>::Read r = s.read(); + for(int i=0;i<len;i++) { + if (i==0) + rect.pos=r[i]; + else + rect.expand_to(r[i]); + } + + return rect; + +} + void ConcavePolygonShape2D::_bind_methods() { diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h index b835096b2a..29666c88c1 100644 --- a/scene/resources/concave_polygon_shape_2d.h +++ b/scene/resources/concave_polygon_shape_2d.h @@ -41,6 +41,9 @@ public: void set_segments(const DVector<Vector2>& p_segments); DVector<Vector2> get_segments() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const ; + ConcavePolygonShape2D(); }; diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp index 326a0e5180..6a405c9c94 100644 --- a/scene/resources/convex_polygon_shape.cpp +++ b/scene/resources/convex_polygon_shape.cpp @@ -28,7 +28,34 @@ /*************************************************************************/ #include "convex_polygon_shape.h" #include "servers/physics_server.h" +#include "quick_hull.h" +Vector<Vector3> ConvexPolygonShape::_gen_debug_mesh_lines() { + + DVector<Vector3> points = get_points(); + + if (points.size()>3) { + + QuickHull qh; + Vector<Vector3> varr = Variant(points); + Geometry::MeshData md; + Error err = qh.build(varr,md); + if (err==OK) { + Vector<Vector3> lines; + lines.resize(md.edges.size()*2); + for(int i=0;i<md.edges.size();i++) { + lines[i*2+0]=md.vertices[md.edges[i].a]; + lines[i*2+1]=md.vertices[md.edges[i].b]; + } + return lines; + + + } + + } + + return Vector<Vector3>(); +} void ConvexPolygonShape::_update_shape() { diff --git a/scene/resources/convex_polygon_shape.h b/scene/resources/convex_polygon_shape.h index e0a590e09d..48454deb2b 100644 --- a/scene/resources/convex_polygon_shape.h +++ b/scene/resources/convex_polygon_shape.h @@ -42,6 +42,7 @@ protected: virtual void _update_shape(); + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: void set_points(const DVector<Vector3>& p_points); diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp index 74506f8600..dac39fc846 100644 --- a/scene/resources/convex_polygon_shape_2d.cpp +++ b/scene/resources/convex_polygon_shape_2d.cpp @@ -29,7 +29,7 @@ #include "convex_polygon_shape_2d.h" #include "servers/physics_2d_server.h" - +#include "servers/visual_server.h" void ConvexPolygonShape2D::_update_shape() { Physics2DServer::get_singleton()->shape_set_data(get_rid(),points); @@ -66,6 +66,29 @@ void ConvexPolygonShape2D::_bind_methods() { } +void ConvexPolygonShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + + Vector<Color> col; + col.push_back(p_color); + VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid,points,col); +} + +Rect2 ConvexPolygonShape2D::get_rect() const { + + + Rect2 rect; + for(int i=0;i<points.size();i++) { + if (i==0) + rect.pos=points[i]; + else + rect.expand_to(points[i]); + } + + return rect; + +} + ConvexPolygonShape2D::ConvexPolygonShape2D() : Shape2D( Physics2DServer::get_singleton()->shape_create(Physics2DServer::SHAPE_CONVEX_POLYGON)) { diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h index efcaa19be6..1af7787f67 100644 --- a/scene/resources/convex_polygon_shape_2d.h +++ b/scene/resources/convex_polygon_shape_2d.h @@ -45,6 +45,9 @@ public: void set_points(const Vector<Vector2>& p_points); Vector<Vector2> get_points() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const ; + ConvexPolygonShape2D(); }; diff --git a/scene/resources/gibberish_stream.cpp b/scene/resources/gibberish_stream.cpp index 23b94c8f38..7af81bd992 100644 --- a/scene/resources/gibberish_stream.cpp +++ b/scene/resources/gibberish_stream.cpp @@ -29,6 +29,8 @@ #include "gibberish_stream.h" #include "servers/audio_server.h" +#if 0 + int AudioStreamGibberish::get_channel_count() const { return 1; @@ -328,3 +330,4 @@ AudioStreamGibberish::AudioStreamGibberish() { paused=false; active_voices=0; } +#endif diff --git a/scene/resources/gibberish_stream.h b/scene/resources/gibberish_stream.h index a52e629f83..77393db9f4 100644 --- a/scene/resources/gibberish_stream.h +++ b/scene/resources/gibberish_stream.h @@ -29,7 +29,7 @@ #ifndef GIBBERISH_STREAM_H #define GIBBERISH_STREAM_H - +#if 0 #include "scene/resources/audio_stream.h" #include "scene/resources/sample_library.h" class AudioStreamGibberish : public AudioStream { @@ -109,4 +109,6 @@ public: AudioStreamGibberish(); }; +#endif + #endif // GIBBERISH_STREAM_H diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 6c7fa545d4..0546addd3e 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -32,6 +32,15 @@ #include "resource.h" #include "scene/main/node.h" +//changes: +//1-make the InstanceState a reference inside the resource that can be shared +//2-make the instance "editable" with a flag, save here and load here, no need for property +//3-properly save modifications in sub-scene +//4-add scene inheritance +//5-chain of instance states in editor? (to check what was modified) +//6-saving will be hell + + class PackedScene : public Resource { OBJ_TYPE( PackedScene, Resource ); diff --git a/scene/resources/plane_shape.cpp b/scene/resources/plane_shape.cpp index 150406ceff..760a36a91e 100644 --- a/scene/resources/plane_shape.cpp +++ b/scene/resources/plane_shape.cpp @@ -30,7 +30,34 @@ #include "servers/physics_server.h" - +Vector<Vector3> PlaneShape::_gen_debug_mesh_lines() { + + Plane p = get_plane(); + Vector<Vector3> points; + + Vector3 n1 = p.get_any_perpendicular_normal(); + Vector3 n2 = p.normal.cross(n1).normalized(); + + Vector3 pface[4]={ + p.normal*p.d+n1*10.0+n2*10.0, + p.normal*p.d+n1*10.0+n2*-10.0, + p.normal*p.d+n1*-10.0+n2*-10.0, + p.normal*p.d+n1*-10.0+n2*10.0, + }; + + points.push_back(pface[0]); + points.push_back(pface[1]); + points.push_back(pface[1]); + points.push_back(pface[2]); + points.push_back(pface[2]); + points.push_back(pface[3]); + points.push_back(pface[3]); + points.push_back(pface[0]); + points.push_back(p.normal*p.d); + points.push_back(p.normal*p.d+p.normal*3); + + return points; +} void PlaneShape::_update_shape() { diff --git a/scene/resources/plane_shape.h b/scene/resources/plane_shape.h index 3bdf8f2bef..dd285171c4 100644 --- a/scene/resources/plane_shape.h +++ b/scene/resources/plane_shape.h @@ -39,9 +39,9 @@ class PlaneShape : public Shape { protected: static void _bind_methods(); - virtual void _update_shape(); + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: void set_plane(Plane p_plane); diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp index e12ecf107b..ee55cc6e37 100644 --- a/scene/resources/ray_shape.cpp +++ b/scene/resources/ray_shape.cpp @@ -30,7 +30,14 @@ #include "servers/physics_server.h" +Vector<Vector3> RayShape::_gen_debug_mesh_lines() { + Vector<Vector3> points; + points.push_back(Vector3()); + points.push_back(Vector3(0,0,get_length())); + + return points; +} void RayShape::_update_shape() { diff --git a/scene/resources/ray_shape.h b/scene/resources/ray_shape.h index 0b6156d343..edb29b83b5 100644 --- a/scene/resources/ray_shape.h +++ b/scene/resources/ray_shape.h @@ -39,7 +39,7 @@ protected: static void _bind_methods(); virtual void _update_shape(); - + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: void set_length(float p_length); diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp index d3332f45a5..7903d88736 100644 --- a/scene/resources/rectangle_shape_2d.cpp +++ b/scene/resources/rectangle_shape_2d.cpp @@ -29,7 +29,7 @@ #include "rectangle_shape_2d.h" #include "servers/physics_2d_server.h" - +#include "servers/visual_server.h" void RectangleShape2D::_update_shape() { Physics2DServer::get_singleton()->shape_set_data(get_rid(),extents); @@ -48,6 +48,19 @@ Vector2 RectangleShape2D::get_extents() const { return extents; } +void RectangleShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + + VisualServer::get_singleton()->canvas_item_add_rect(p_to_rid,Rect2(-extents,extents*2.0),p_color); + +} + +Rect2 RectangleShape2D::get_rect() const { + + return Rect2(-extents,extents*2.0); + +} + void RectangleShape2D::_bind_methods() { diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h index 0b89441d04..96de02fb70 100644 --- a/scene/resources/rectangle_shape_2d.h +++ b/scene/resources/rectangle_shape_2d.h @@ -44,6 +44,9 @@ public: void set_extents(const Vector2& p_extents); Vector2 get_extents() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const ; + RectangleShape2D(); }; diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp index b8bd3de552..88f7adcd9b 100644 --- a/scene/resources/segment_shape_2d.cpp +++ b/scene/resources/segment_shape_2d.cpp @@ -29,6 +29,7 @@ #include "segment_shape_2d.h" #include "servers/physics_2d_server.h" +#include "servers/visual_server.h" void SegmentShape2D::_update_shape() { @@ -62,6 +63,23 @@ Vector2 SegmentShape2D::get_b() const { return b; } +void SegmentShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + VisualServer::get_singleton()->canvas_item_add_line(p_to_rid,a,b,p_color,3); +} + +Rect2 SegmentShape2D::get_rect() const{ + + Rect2 rect; + rect.pos=a; + rect.expand_to(b); + return rect; + +} + + + + void SegmentShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_a","a"),&SegmentShape2D::set_a); @@ -94,6 +112,37 @@ void RayShape2D::_update_shape() { } + +void RayShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + + Vector2 tip = Vector2(0,get_length()); + VS::get_singleton()->canvas_item_add_line(p_to_rid,Vector2(),tip,p_color,3); + Vector<Vector2> pts; + float tsize=4; + pts.push_back(tip+Vector2(0,tsize)); + pts.push_back(tip+Vector2(0.707*tsize,0)); + pts.push_back(tip+Vector2(-0.707*tsize,0)); + Vector<Color> cols; + for(int i=0;i<3;i++) + cols.push_back(p_color); + + VS::get_singleton()->canvas_item_add_primitive(p_to_rid,pts,cols,Vector<Point2>(),RID()); + + + +} + +Rect2 RayShape2D::get_rect() const { + + Rect2 rect; + rect.pos=Vector2(); + rect.expand_to(Vector2(0,length)); + rect=rect.grow(0.707*4); + return rect; +} + + void RayShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_length","length"),&RayShape2D::set_length); diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h index ec771cd2ed..37c68b6c92 100644 --- a/scene/resources/segment_shape_2d.h +++ b/scene/resources/segment_shape_2d.h @@ -49,6 +49,9 @@ public: Vector2 get_a() const; Vector2 get_b() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const; + SegmentShape2D(); }; @@ -67,6 +70,8 @@ public: void set_length(real_t p_length); real_t get_length() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const; RayShape2D(); }; diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp index 1120a8d672..143ef82d51 100644 --- a/scene/resources/shape.cpp +++ b/scene/resources/shape.cpp @@ -29,9 +29,67 @@ #include "shape.h" #include "servers/physics_server.h" +#include "scene/resources/mesh.h" +#include "os/os.h" +#include "scene/main/scene_main_loop.h" +void Shape::add_vertices_to_array(DVector<Vector3> &array, const Transform& p_xform) { + Vector<Vector3> toadd = _gen_debug_mesh_lines(); + + if (toadd.size()) { + + int base=array.size(); + array.resize(base+toadd.size()); + DVector<Vector3>::Write w = array.write(); + for(int i=0;i<toadd.size();i++) { + w[i+base]=p_xform.xform(toadd[i]); + } + + } +} + +Ref<Mesh> Shape::get_debug_mesh() { + + if (debug_mesh_cache.is_valid()) + return debug_mesh_cache; + + Vector<Vector3> lines = _gen_debug_mesh_lines(); + + debug_mesh_cache = Ref<Mesh>(memnew(Mesh)); + + if (!lines.empty()) { + //make mesh + DVector<Vector3> array; + array.resize(lines.size()); + { + + DVector<Vector3>::Write w=array.write(); + for(int i=0;i<lines.size();i++) { + w[i]=lines[i]; + } + } + + Array arr; + arr.resize(Mesh::ARRAY_MAX); + arr[Mesh::ARRAY_VERTEX]=array; + + SceneTree *st=OS::get_singleton()->get_main_loop()->cast_to<SceneTree>(); + + debug_mesh_cache->add_surface(Mesh::PRIMITIVE_LINES,arr); + + if (st) { + debug_mesh_cache->surface_set_material(0,st->get_debug_collision_material()); + } + + } + + + + return debug_mesh_cache; + +} Shape::Shape() { @@ -49,3 +107,4 @@ Shape::~Shape() { PhysicsServer::get_singleton()->free(shape); } + diff --git a/scene/resources/shape.h b/scene/resources/shape.h index 3cc806c7a3..1992ce51c3 100644 --- a/scene/resources/shape.h +++ b/scene/resources/shape.h @@ -30,6 +30,7 @@ #define SHAPE_H #include "resource.h" +class Mesh; class Shape : public Resource { @@ -38,13 +39,22 @@ class Shape : public Resource { RES_BASE_EXTENSION("shp"); RID shape; + Ref<Mesh> debug_mesh_cache; + protected: _FORCE_INLINE_ RID get_shape() const { return shape; } Shape(RID p_shape); + + virtual Vector<Vector3> _gen_debug_mesh_lines()=0;// { return Vector<Vector3>(); } public: virtual RID get_rid() const { return shape; } + + Ref<Mesh> get_debug_mesh(); + + void add_vertices_to_array(DVector<Vector3> &array, const Transform& p_xform); + Shape(); ~Shape(); }; diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h index 55f3173db4..1737301d9d 100644 --- a/scene/resources/shape_2d.h +++ b/scene/resources/shape_2d.h @@ -53,6 +53,8 @@ public: Variant collide_with_motion_and_get_contacts(const Matrix32& p_local_xform, const Vector2& p_local_motion, const Ref<Shape2D>& p_shape, const Matrix32& p_shape_xform, const Vector2 &p_p_shape_motion); Variant collide_and_get_contacts(const Matrix32& p_local_xform, const Ref<Shape2D>& p_shape, const Matrix32& p_shape_xform); + virtual void draw(const RID& p_to_rid,const Color& p_color) {} + virtual Rect2 get_rect() const { return Rect2(); } virtual RID get_rid() const; Shape2D(); ~Shape2D(); diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp index d4dc46d64f..c660b604f3 100644 --- a/scene/resources/shape_line_2d.cpp +++ b/scene/resources/shape_line_2d.cpp @@ -28,7 +28,7 @@ /*************************************************************************/ #include "shape_line_2d.h" #include "servers/physics_2d_server.h" - +#include "servers/visual_server.h" void LineShape2D::_update_shape() { Array arr; @@ -61,6 +61,32 @@ real_t LineShape2D::get_d() const { return d; } + +void LineShape2D::draw(const RID& p_to_rid,const Color& p_color) { + + Vector2 point = get_d() * get_normal(); + + Vector2 l1[2]={point-get_normal().tangent()*100,point+get_normal().tangent()*100}; + VS::get_singleton()->canvas_item_add_line(p_to_rid,l1[0],l1[1],p_color,3); + Vector2 l2[2]={point,point+get_normal()*30}; + VS::get_singleton()->canvas_item_add_line(p_to_rid,l2[0],l2[1],p_color,3); + +} +Rect2 LineShape2D::get_rect() const{ + + Vector2 point = get_d() * get_normal(); + + Vector2 l1[2]={point-get_normal().tangent()*100,point+get_normal().tangent()*100}; + Vector2 l2[2]={point,point+get_normal()*30}; + Rect2 rect; + rect.pos=l1[0]; + rect.expand_to(l1[1]); + rect.expand_to(l2[0]); + rect.expand_to(l2[1]); + return rect; + +} + void LineShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_normal","normal"),&LineShape2D::set_normal); diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h index 3ba8f57add..f32ad7fb7c 100644 --- a/scene/resources/shape_line_2d.h +++ b/scene/resources/shape_line_2d.h @@ -49,6 +49,9 @@ public: Vector2 get_normal() const; real_t get_d() const; + virtual void draw(const RID& p_to_rid,const Color& p_color); + virtual Rect2 get_rect() const; + LineShape2D(); }; diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp index e93d718efa..a7e28eb727 100644 --- a/scene/resources/sphere_shape.cpp +++ b/scene/resources/sphere_shape.cpp @@ -29,6 +29,30 @@ #include "sphere_shape.h" #include "servers/physics_server.h" +Vector<Vector3> SphereShape::_gen_debug_mesh_lines() { + + float r=get_radius(); + + Vector<Vector3> points; + + for(int i=0;i<=360;i++) { + + float ra=Math::deg2rad(i); + float rb=Math::deg2rad(i+1); + Point2 a = Vector2(Math::sin(ra),Math::cos(ra))*r; + Point2 b = Vector2(Math::sin(rb),Math::cos(rb))*r; + + points.push_back(Vector3(a.x,0,a.y)); + points.push_back(Vector3(b.x,0,b.y)); + points.push_back(Vector3(0,a.x,a.y)); + points.push_back(Vector3(0,b.x,b.y)); + points.push_back(Vector3(a.x,a.y,0)); + points.push_back(Vector3(b.x,b.y,0)); + + } + + return points; +} void SphereShape::_update_shape() { diff --git a/scene/resources/sphere_shape.h b/scene/resources/sphere_shape.h index 1bbddb9fd9..2543d94439 100644 --- a/scene/resources/sphere_shape.h +++ b/scene/resources/sphere_shape.h @@ -42,7 +42,7 @@ protected: static void _bind_methods(); virtual void _update_shape(); - + virtual Vector<Vector3> _gen_debug_mesh_lines(); public: void set_radius(float p_radius); diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp index b27413bb68..c957fd4c67 100644 --- a/scene/resources/video_stream.cpp +++ b/scene/resources/video_stream.cpp @@ -28,16 +28,12 @@ /*************************************************************************/ #include "video_stream.h" -void VideoStream::_bind_methods() { +void VideoStreamPlayback::_bind_methods() { - ObjectTypeDB::bind_method(_MD("get_pending_frame_count"),&VideoStream::get_pending_frame_count); - ObjectTypeDB::bind_method(_MD("pop_frame"),&VideoStream::pop_frame); - ObjectTypeDB::bind_method(_MD("peek_frame"),&VideoStream::peek_frame); - ObjectTypeDB::bind_method(_MD("set_audio_track","idx"),&VideoStream::set_audio_track); }; -VideoStream::VideoStream() { +VideoStreamPlayback::VideoStreamPlayback() { }; diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h index 2ad7457ec4..a23ef0c64f 100644 --- a/scene/resources/video_stream.h +++ b/scene/resources/video_stream.h @@ -33,15 +33,17 @@ #include "scene/resources/texture.h" -class VideoStream : public Resource { +class VideoStreamPlayback : public Resource { - OBJ_TYPE(VideoStream,Resource); + OBJ_TYPE(VideoStreamPlayback,Resource); protected: static void _bind_methods(); public: + typedef int (*AudioMixCallback)(void* p_udata,const int16_t *p_data,int p_frames); + virtual void stop()=0; virtual void play()=0; @@ -58,16 +60,34 @@ public: virtual float get_pos() const=0; virtual void seek_pos(float p_time)=0; - virtual int get_pending_frame_count() const=0; - virtual void pop_frame(Ref<ImageTexture> p_tex)=0; - virtual Image peek_frame() const=0; - virtual void set_audio_track(int p_idx) =0; - virtual void update(float p_time)=0; + //virtual int mix(int16_t* p_bufer,int p_frames)=0; + + virtual Ref<Texture> get_texture()=0; + virtual void update(float p_delta)=0; - VideoStream(); + virtual void set_mix_callback(AudioMixCallback p_callback,void *p_userdata)=0; + virtual int get_channels() const=0; + virtual int get_mix_rate() const=0; + + VideoStreamPlayback(); }; + +class VideoStream : public Resource { + + OBJ_TYPE( VideoStream, Resource ); + OBJ_SAVE_TYPE( VideoStream ); //children are all saved as AudioStream, so they can be exchanged + +public: + + virtual void set_audio_track(int p_track)=0; + virtual Ref<VideoStreamPlayback> instance_playback()=0; + + VideoStream() {} +}; + + #endif |