diff options
Diffstat (limited to 'scene')
169 files changed, 7347 insertions, 1097 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index b49426f7e2..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); @@ -149,11 +151,14 @@ void AnimatedSprite::_notification(int p_what) { Size2i s; s = texture->get_size(); - Point2i ofs=offset; + Point2 ofs=offset; if (centered) ofs-=s/2; - Rect2i dst_rect(ofs,s); + if (OS::get_singleton()->get_use_pixel_snap()) { + ofs=ofs.floor(); + } + Rect2 dst_rect(ofs,s); if (hflip) dst_rect.size.x=-dst_rect.size.x; @@ -284,7 +289,7 @@ Rect2 AnimatedSprite::get_item_rect() const { return Node2D::get_item_rect(); Size2i s = t->get_size(); - Point2i ofs=offset; + Point2 ofs=offset; if (centered) ofs-=s/2; @@ -330,11 +335,11 @@ void AnimatedSprite::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "frames",PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); - ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); + ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); } diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index f9e79e25bc..c44b46adbf 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -428,8 +428,9 @@ void Area2D::set_enable_monitoring(bool p_enable) { if (monitoring) { - Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout"); - Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,"_area_inout"); + Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_body_inout); + Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_area_inout); + } else { Physics2DServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName()); Physics2DServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName()); @@ -652,17 +653,17 @@ void Area2D::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale")); + ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); + ADD_PROPERTYNZ( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask")); + ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); + ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable")); + ADD_PROPERTYNO( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); + ADD_PROPERTYNO( PropertyInfo(Variant::INT,"collision/mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_mask"),_SCS("get_collision_mask")); } diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp index 245b3ba7eb..7a138830db 100644 --- a/scene/2d/back_buffer_copy.cpp +++ b/scene/2d/back_buffer_copy.cpp @@ -4,7 +4,7 @@ void BackBufferCopy::_update_copy_mode() { switch(copy_mode) { - case COPY_MODE_DISALED: { + case COPY_MODE_DISABLED: { VS::get_singleton()->canvas_item_set_copy_to_backbuffer(get_canvas_item(),false,Rect2()); } break; @@ -58,7 +58,7 @@ void BackBufferCopy::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"copy_mode",PROPERTY_HINT_ENUM,"Disabled,Rect,Viewport"),_SCS("set_copy_mode"),_SCS("get_copy_mode")); ADD_PROPERTY( PropertyInfo(Variant::RECT2,"rect"),_SCS("set_rect"),_SCS("get_rect")); - BIND_CONSTANT( COPY_MODE_DISALED ); + BIND_CONSTANT( COPY_MODE_DISABLED ); BIND_CONSTANT( COPY_MODE_RECT ); BIND_CONSTANT( COPY_MODE_VIEWPORT ); diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h index 3a86ffa309..734cad458a 100644 --- a/scene/2d/back_buffer_copy.h +++ b/scene/2d/back_buffer_copy.h @@ -7,7 +7,7 @@ class BackBufferCopy : public Node2D { OBJ_TYPE( BackBufferCopy,Node2D); public: enum CopyMode { - COPY_MODE_DISALED, + COPY_MODE_DISABLED, COPY_MODE_RECT, COPY_MODE_VIEWPORT }; diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index 70b88a6611..49683da226 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -81,43 +81,47 @@ Matrix32 Camera2D::get_camera_transform() { if (!first) { - if (centered) { + if (anchor_mode==ANCHOR_MODE_DRAG_CENTER) { - if (h_drag_enabled) { - camera_pos.x = MIN( camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT])); - camera_pos.x = MAX( camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT])); - } else { + if (h_drag_enabled) { + camera_pos.x = MIN( camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT])); + camera_pos.x = MAX( camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT])); + } else { - if (h_ofs<0) { - camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; - } else { - camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; - } - } + if (h_ofs<0) { + camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT] * h_ofs; + } else { + camera_pos.x = new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_LEFT] * h_ofs; + } + } + + if (v_drag_enabled) { - if (v_drag_enabled) { + camera_pos.y = MIN( camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM])); + camera_pos.y = MAX( camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP])); - camera_pos.y = MIN( camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM])); - camera_pos.y = MAX( camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP])); + } else { - } else { + if (v_ofs<0) { + camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; + } else { + camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; + } + } - if (v_ofs<0) { - camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_TOP] * v_ofs; - } else { - camera_pos.y = new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM] * v_ofs; - } - } + } else if (anchor_mode==ANCHOR_MODE_FIXED_TOP_LEFT){ + camera_pos=new_camera_pos; } + if (smoothing>0.0) { float c = smoothing*get_fixed_process_delta_time(); smoothed_camera_pos = ((new_camera_pos-smoothed_camera_pos)*c)+smoothed_camera_pos; ret_camera_pos=smoothed_camera_pos; -// camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing; + // camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing; } else { ret_camera_pos=smoothed_camera_pos=camera_pos; @@ -132,7 +136,7 @@ Matrix32 Camera2D::get_camera_transform() { } - Point2 screen_offset = (centered ? (screen_size * 0.5 * zoom) : Point2()); + Point2 screen_offset = (anchor_mode==ANCHOR_MODE_DRAG_CENTER ? (screen_size * 0.5 * zoom) : Point2()); float angle = get_global_transform().get_rotation(); if(rotating){ @@ -267,15 +271,15 @@ Vector2 Camera2D::get_offset() const{ return offset; } -void Camera2D::set_centered(bool p_centered){ +void Camera2D::set_anchor_mode(AnchorMode p_anchor_mode){ - centered=p_centered; + anchor_mode=p_anchor_mode; _update_scroll(); } -bool Camera2D::is_centered() const { +Camera2D::AnchorMode Camera2D::get_anchor_mode() const { - return centered; + return anchor_mode; } void Camera2D::set_rotating(bool p_rotating){ @@ -439,8 +443,8 @@ void Camera2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_offset","offset"),&Camera2D::set_offset); ObjectTypeDB::bind_method(_MD("get_offset"),&Camera2D::get_offset); - ObjectTypeDB::bind_method(_MD("set_centered","centered"),&Camera2D::set_centered); - ObjectTypeDB::bind_method(_MD("is_centered"),&Camera2D::is_centered); + ObjectTypeDB::bind_method(_MD("set_anchor_mode","anchor_mode"),&Camera2D::set_anchor_mode); + ObjectTypeDB::bind_method(_MD("get_anchor_mode"),&Camera2D::get_anchor_mode); ObjectTypeDB::bind_method(_MD("set_rotating","rotating"),&Camera2D::set_rotating); ObjectTypeDB::bind_method(_MD("is_rotating"),&Camera2D::is_rotating); @@ -487,7 +491,7 @@ void Camera2D::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_offset"),_SCS("get_offset")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"centered"),_SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"anchor_mode",PROPERTY_HINT_ENUM,"Fixed TopLeft,Drag Center"),_SCS("set_anchor_mode"),_SCS("get_anchor_mode")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"rotating"),_SCS("set_rotating"),_SCS("is_rotating")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"current"),_SCS("_set_current"),_SCS("is_current")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"smoothing"),_SCS("set_follow_smoothing"),_SCS("get_follow_smoothing") ); @@ -507,6 +511,8 @@ void Camera2D::_bind_methods() { ADD_PROPERTYI( PropertyInfo(Variant::REAL,"drag_margin/bottom",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_drag_margin"),_SCS("get_drag_margin"),MARGIN_BOTTOM); + BIND_CONSTANT( ANCHOR_MODE_DRAG_CENTER ); + BIND_CONSTANT( ANCHOR_MODE_FIXED_TOP_LEFT ); } @@ -514,7 +520,7 @@ Camera2D::Camera2D() { - centered=true; + anchor_mode=ANCHOR_MODE_DRAG_CENTER; rotating=false; current=false; limit[MARGIN_LEFT]=-10000000; diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h index 8975a2584b..79d84f48d0 100644 --- a/scene/2d/camera_2d.h +++ b/scene/2d/camera_2d.h @@ -36,6 +36,12 @@ class Camera2D : public Node2D { OBJ_TYPE( Camera2D, Node2D ); +public: + + enum AnchorMode { + ANCHOR_MODE_FIXED_TOP_LEFT, + ANCHOR_MODE_DRAG_CENTER + }; protected: Point2 camera_pos; @@ -49,7 +55,7 @@ protected: RID canvas; Vector2 offset; Vector2 zoom; - bool centered; + AnchorMode anchor_mode; bool rotating; bool current; float smoothing; @@ -77,8 +83,8 @@ public: void set_offset(const Vector2& p_offset); Vector2 get_offset() const; - void set_centered(bool p_centered); - bool is_centered() const; + void set_anchor_mode(AnchorMode p_anchor_mode); + AnchorMode get_anchor_mode() const; void set_rotating(bool p_rotating); bool is_rotating() const; @@ -120,4 +126,6 @@ public: Camera2D(); }; +VARIANT_ENUM_CAST(Camera2D::AnchorMode); + #endif // CAMERA_2D_H diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index 6a1ea0728d..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); } @@ -1071,8 +1071,8 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("draw_rect","rect","color"),&CanvasItem::draw_rect); ObjectTypeDB::bind_method(_MD("draw_circle","pos","radius","color"),&CanvasItem::draw_circle); ObjectTypeDB::bind_method(_MD("draw_texture","texture:Texture","pos"),&CanvasItem::draw_texture); - ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate"),&CanvasItem::draw_texture_rect,DEFVAL(false),DEFVAL(Color(1,1,1))); - ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1))); + ObjectTypeDB::bind_method(_MD("draw_texture_rect","texture:Texture","rect","tile","modulate","transpose"),&CanvasItem::draw_texture_rect,DEFVAL(Color(1,1,1)),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("draw_texture_rect_region","texture:Texture","rect","src_rect","modulate","transpose"),&CanvasItem::draw_texture_rect_region,DEFVAL(Color(1,1,1)),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("draw_style_box","style_box:StyleBox","rect"),&CanvasItem::draw_style_box); ObjectTypeDB::bind_method(_MD("draw_primitive","points","colors","uvs","texture:Texture","width"),&CanvasItem::draw_primitive,DEFVAL(Array()),DEFVAL(Ref<Texture>()),DEFVAL(1.0)); ObjectTypeDB::bind_method(_MD("draw_polygon","points","colors","uvs","texture:Texture"),&CanvasItem::draw_polygon,DEFVAL(Array()),DEFVAL(Ref<Texture>())); @@ -1103,14 +1103,14 @@ void CanvasItem::_bind_methods() { BIND_VMETHOD(MethodInfo("_draw")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") ); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") ); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") ); + ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"),_SCS("_is_visible_") ); + ADD_PROPERTYNO( PropertyInfo(Variant::REAL,"visibility/opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_opacity"),_SCS("get_opacity") ); + ADD_PROPERTYNO( PropertyInfo(Variant::REAL,"visibility/self_opacity",PROPERTY_HINT_RANGE, "0,1,0.01"), _SCS("set_self_opacity"),_SCS("get_self_opacity") ); ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/on_top",PROPERTY_HINT_NONE,"",0), _SCS("_set_on_top"),_SCS("_is_on_top") ); //compatibility ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/blend_mode",PROPERTY_HINT_ENUM, "Mix,Add,Sub,Mul,PMAlpha"), _SCS("set_blend_mode"),_SCS("get_blend_mode") ); - ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") ); + ADD_PROPERTYNO( PropertyInfo(Variant::INT,"visibility/light_mask",PROPERTY_HINT_ALL_FLAGS), _SCS("set_light_mask"),_SCS("get_light_mask") ); ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"material/material",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemMaterial"), _SCS("set_material"),_SCS("get_material") ); ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"material/use_parent"), _SCS("set_use_parent_material"),_SCS("get_use_parent_material") ); //exporting these two things doesn't really make much sense i think @@ -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_object_2d.cpp b/scene/2d/collision_object_2d.cpp index f577b81598..8b8caf13d3 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -115,19 +115,16 @@ void CollisionObject2D::_update_shapes() { bool CollisionObject2D::_set(const StringName& p_name, const Variant& p_value) { String name=p_name; - if (name=="shape_count") { + if (name.begins_with("shapes/")) { - shapes.resize(p_value); - _update_shapes(); - _change_notify(); - - } else if (name.begins_with("shapes/")) { - - int idx=name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); - if (what=="shape") - set_shape(idx,RefPtr(p_value)); - else if (what=="transform") + int idx=name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); + if (what=="shape") { + if (idx>=shapes.size()) + add_shape(RefPtr(p_value)); + else + set_shape(idx,RefPtr(p_value)); + } else if (what=="transform") set_shape_transform(idx,p_value); else if (what=="trigger") set_shape_as_trigger(idx,p_value); @@ -143,12 +140,10 @@ bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const { String name=p_name; - if (name=="shape_count") { - r_ret= shapes.size(); - } else if (name.begins_with("shapes/")) { + if (name.begins_with("shapes/")) { - int idx=name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int idx=name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="shape") r_ret= get_shape(idx); else if (what=="transform") @@ -163,7 +158,7 @@ bool CollisionObject2D::_get(const StringName& p_name,Variant &r_ret) const { void CollisionObject2D::_get_property_list( List<PropertyInfo> *p_list) const { - p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + //p_list->push_back( PropertyInfo(Variant::INT,"shape_count",PROPERTY_HINT_RANGE,"0,256,1",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); for(int i=0;i<shapes.size();i++) { String path="shapes/"+itos(i)+"/"; @@ -254,12 +249,19 @@ void CollisionObject2D::_bind_methods() { void CollisionObject2D::add_shape(const Ref<Shape2D>& p_shape, const Matrix32& p_transform) { + ERR_FAIL_COND(p_shape.is_null()); + ShapeData sdata; sdata.shape=p_shape; sdata.xform=p_transform; sdata.trigger=false; - shapes.push_back(sdata); - _update_shapes(); + + if (area) + Physics2DServer::get_singleton()->area_add_shape(get_rid(),p_shape->get_rid(),p_transform); + else + Physics2DServer::get_singleton()->body_add_shape(get_rid(),p_shape->get_rid(),p_transform); + + shapes.push_back(sdata); } int CollisionObject2D::get_shape_count() const { @@ -270,8 +272,15 @@ int CollisionObject2D::get_shape_count() const { void CollisionObject2D::set_shape(int p_shape_idx, const Ref<Shape2D>& p_shape) { ERR_FAIL_INDEX(p_shape_idx,shapes.size()); + ERR_FAIL_COND(p_shape.is_null()); + shapes[p_shape_idx].shape=p_shape; - _update_shapes(); + if (area) + Physics2DServer::get_singleton()->area_set_shape(get_rid(),p_shape_idx,p_shape->get_rid()); + else + Physics2DServer::get_singleton()->body_set_shape(get_rid(),p_shape_idx,p_shape->get_rid()); + +// _update_shapes(); } void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_transform) { @@ -279,7 +288,12 @@ void CollisionObject2D::set_shape_transform(int p_shape_idx, const Matrix32& p_t ERR_FAIL_INDEX(p_shape_idx,shapes.size()); shapes[p_shape_idx].xform=p_transform; - _update_shapes(); + if (area) + Physics2DServer::get_singleton()->area_set_shape_transform(get_rid(),p_shape_idx,p_transform); + else + Physics2DServer::get_singleton()->body_set_shape_transform(get_rid(),p_shape_idx,p_transform); + +// _update_shapes(); } Ref<Shape2D> CollisionObject2D::get_shape(int p_shape_idx) const { 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/joints_2d.cpp b/scene/2d/joints_2d.cpp index c1e91c2ecd..1df936535f 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -126,7 +126,7 @@ void Joint2D::_bind_methods() { ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_a"), _SCS("set_node_a"),_SCS("get_node_a") ); ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "node_b"), _SCS("set_node_b"),_SCS("get_node_b") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.01"), _SCS("set_bias"),_SCS("get_bias") ); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "bias/bias",PROPERTY_HINT_RANGE,"0,0.9,0.001"), _SCS("set_bias"),_SCS("get_bias") ); } @@ -175,15 +175,37 @@ RID PinJoint2D::_configure_joint() { //add a collision exception between both Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(),body_b->get_rid()); } + RID pj = Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID()); + Physics2DServer::get_singleton()->pin_joint_set_param(pj, Physics2DServer::PIN_JOINT_SOFTNESS, softness); + return pj; - return Physics2DServer::get_singleton()->pin_joint_create(get_global_transform().get_origin(),body_a->get_rid(),body_b?body_b->get_rid():RID()); +} + +void PinJoint2D::set_softness(real_t p_softness) { + + softness=p_softness; + update(); + if (get_joint().is_valid()) + Physics2DServer::get_singleton()->pin_joint_set_param(get_joint(), Physics2DServer::PIN_JOINT_SOFTNESS, p_softness); } +real_t PinJoint2D::get_softness() const { -PinJoint2D::PinJoint2D() { + return softness; +} + +void PinJoint2D::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_softness","softness"), &PinJoint2D::set_softness); + ObjectTypeDB::bind_method(_MD("get_softness"), &PinJoint2D::get_softness); + ADD_PROPERTY( PropertyInfo( Variant::REAL, "softness", PROPERTY_HINT_EXP_RANGE,"0.00,16,0.01"), _SCS("set_softness"), _SCS("get_softness")); +} + +PinJoint2D::PinJoint2D() { + softness = 0; } diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h index ac72c6ce59..908e3a158e 100644 --- a/scene/2d/joints_2d.h +++ b/scene/2d/joints_2d.h @@ -72,13 +72,17 @@ class PinJoint2D : public Joint2D { OBJ_TYPE(PinJoint2D,Joint2D); + real_t softness; + protected: void _notification(int p_what); virtual RID _configure_joint(); + static void _bind_methods(); public: - + void set_softness(real_t p_stiffness); + real_t get_softness() const; PinJoint2D(); }; diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp index c0ab544d42..852a6fb46b 100644 --- a/scene/2d/light_2d.cpp +++ b/scene/2d/light_2d.cpp @@ -237,6 +237,16 @@ float Light2D::get_shadow_esm_multiplier() const{ return shadow_esm_multiplier; } +void Light2D::set_shadow_color( const Color& p_shadow_color) { + shadow_color=p_shadow_color; + VS::get_singleton()->canvas_light_set_shadow_color(canvas_light,shadow_color); +} + +Color Light2D::get_shadow_color() const { + return shadow_color; +} + + void Light2D::_notification(int p_what) { @@ -313,6 +323,10 @@ void Light2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_shadow_esm_multiplier","multiplier"),&Light2D::set_shadow_esm_multiplier); ObjectTypeDB::bind_method(_MD("get_shadow_esm_multiplier"),&Light2D::get_shadow_esm_multiplier); + ObjectTypeDB::bind_method(_MD("set_shadow_color","shadow_color"),&Light2D::set_shadow_color); + ObjectTypeDB::bind_method(_MD("get_shadow_color"),&Light2D::get_shadow_color); + + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"offset"),_SCS("set_texture_offset"),_SCS("get_texture_offset")); @@ -327,6 +341,7 @@ void Light2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"range/layer_max",PROPERTY_HINT_RANGE,"-512,512,1"),_SCS("set_layer_range_max"),_SCS("get_layer_range_max")); ADD_PROPERTY( PropertyInfo(Variant::INT,"range/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_mask"),_SCS("get_item_mask")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"shadow/enabled"),_SCS("set_shadow_enabled"),_SCS("is_shadow_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::COLOR,"shadow/color"),_SCS("set_shadow_color"),_SCS("get_shadow_color")); ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/buffer_size",PROPERTY_HINT_RANGE,"32,16384,1"),_SCS("set_shadow_buffer_size"),_SCS("get_shadow_buffer_size")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"shadow/esm_multiplier",PROPERTY_HINT_RANGE,"1,4096,0.1"),_SCS("set_shadow_esm_multiplier"),_SCS("get_shadow_esm_multiplier")); ADD_PROPERTY( PropertyInfo(Variant::INT,"shadow/item_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_item_shadow_mask"),_SCS("get_item_shadow_mask")); @@ -356,6 +371,7 @@ Light2D::Light2D() { shadow_buffer_size=2048; shadow_esm_multiplier=80; energy=1.0; + shadow_color=Color(0,0,0,0); } diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h index ef875aec2f..bf61868bac 100644 --- a/scene/2d/light_2d.h +++ b/scene/2d/light_2d.h @@ -18,6 +18,7 @@ private: bool enabled; bool shadow; Color color; + Color shadow_color; float height; float _scale; float energy; @@ -95,6 +96,10 @@ public: void set_shadow_esm_multiplier( float p_multiplier); float get_shadow_esm_multiplier() const; + void set_shadow_color( const Color& p_shadow_color); + Color get_shadow_color() const; + + virtual Rect2 get_item_rect() const; Light2D(); 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/node_2d.cpp b/scene/2d/node_2d.cpp index 99c33c787d..6141b6a09e 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -398,11 +398,11 @@ void Node2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_relative_transform"),&Node2D::get_relative_transform); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos")); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd")); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative")); + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"transform/pos"),_SCS("set_pos"),_SCS("get_pos")); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"transform/rot",PROPERTY_HINT_RANGE,"-1440,1440,0.1"),_SCS("_set_rotd"),_SCS("_get_rotd")); + ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2,"transform/scale"),_SCS("set_scale"),_SCS("get_scale")); + ADD_PROPERTYNZ(PropertyInfo(Variant::INT,"z/z",PROPERTY_HINT_RANGE,itos(VS::CANVAS_ITEM_Z_MIN)+","+itos(VS::CANVAS_ITEM_Z_MAX)+",1"),_SCS("set_z"),_SCS("get_z")); + ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"z/relative"),_SCS("set_z_as_relative"),_SCS("is_z_relative")); } diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 109546bde3..8bb4eb55ba 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -110,7 +110,10 @@ void ParallaxBackground::_update_scroll() { if (!l) continue; - l->set_base_offset_and_scale(ofs,scale); + if (ignore_camera_zoom) + l->set_base_offset_and_scale(ofs, 1.0); + else + l->set_base_offset_and_scale(ofs, scale); } } @@ -165,6 +168,18 @@ Point2 ParallaxBackground::get_limit_end() const { return limit_end; } +void ParallaxBackground::set_ignore_camera_zoom(bool ignore){ + + ignore_camera_zoom = ignore; + +} + +bool ParallaxBackground::is_ignore_camera_zoom(){ + + return ignore_camera_zoom; + +} + void ParallaxBackground::_bind_methods() { ObjectTypeDB::bind_method(_MD("_camera_moved"),&ParallaxBackground::_camera_moved); @@ -178,6 +193,8 @@ void ParallaxBackground::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_limit_begin"),&ParallaxBackground::get_limit_begin); ObjectTypeDB::bind_method(_MD("set_limit_end","ofs"),&ParallaxBackground::set_limit_end); ObjectTypeDB::bind_method(_MD("get_limit_end"),&ParallaxBackground::get_limit_end); + ObjectTypeDB::bind_method(_MD("set_ignore_camera_zoom"), &ParallaxBackground::set_ignore_camera_zoom); + ObjectTypeDB::bind_method(_MD("is_ignore_camera_zoom"), &ParallaxBackground::is_ignore_camera_zoom); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/offset"),_SCS("set_scroll_offset"),_SCS("get_scroll_offset")); @@ -185,6 +202,7 @@ void ParallaxBackground::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/base_scale"),_SCS("set_scroll_base_scale"),_SCS("get_scroll_base_scale")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_begin"),_SCS("set_limit_begin"),_SCS("get_limit_begin")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"scroll/limit_end"),_SCS("set_limit_end"),_SCS("get_limit_end")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL, "scroll/ignore_camera_zoom"), _SCS("set_ignore_camera_zoom"), _SCS("is_ignore_camera_zoom")); } diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h index 363236b2ad..8dede07a16 100644 --- a/scene/2d/parallax_background.h +++ b/scene/2d/parallax_background.h @@ -44,6 +44,7 @@ class ParallaxBackground : public CanvasLayer { String group_name; Point2 limit_begin; Point2 limit_end; + bool ignore_camera_zoom; void _update_scroll(); protected: @@ -72,6 +73,9 @@ public: void set_limit_end(const Point2& p_ofs); Point2 get_limit_end() const; + void set_ignore_camera_zoom(bool ignore); + bool is_ignore_camera_zoom(); + ParallaxBackground(); }; diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index f0b7c2be60..8f805ceba2 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -1072,19 +1072,19 @@ void Particles2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT,"config/amount",PROPERTY_HINT_EXP_RANGE,"1,1024"),_SCS("set_amount"),_SCS("get_amount") ); ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/lifetime",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_lifetime"),_SCS("get_lifetime") ); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") ); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") ); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") ); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") ); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset")); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space")); - ADD_PROPERTY(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/flip_h"),_SCS("set_flip_h"),_SCS("is_flipped_h")); - ADD_PROPERTY(PropertyInfo(Variant::BOOL,"config/flip_v"),_SCS("set_flip_v"),_SCS("is_flipped_v")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"config/h_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_h_frames"),_SCS("get_h_frames")); - ADD_PROPERTY(PropertyInfo(Variant::INT,"config/v_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_v_frames"),_SCS("get_v_frames")); + ADD_PROPERTYNO(PropertyInfo(Variant::REAL,"config/time_scale",PROPERTY_HINT_EXP_RANGE,"0.01,128,0.01"),_SCS("set_time_scale"),_SCS("get_time_scale") ); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"config/preprocess",PROPERTY_HINT_EXP_RANGE,"0.1,3600,0.1"),_SCS("set_pre_process_time"),_SCS("get_pre_process_time") ); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"config/emit_timeout",PROPERTY_HINT_RANGE,"0,3600,0.1"),_SCS("set_emit_timeout"),_SCS("get_emit_timeout") ); + ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"config/emitting"),_SCS("set_emitting"),_SCS("is_emitting") ); + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"config/offset"),_SCS("set_emissor_offset"),_SCS("get_emissor_offset")); + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"config/half_extents"),_SCS("set_emission_half_extents"),_SCS("get_emission_half_extents")); + ADD_PROPERTYNO(PropertyInfo(Variant::BOOL,"config/local_space"),_SCS("set_use_local_space"),_SCS("is_using_local_space")); + ADD_PROPERTYNO(PropertyInfo(Variant::REAL,"config/explosiveness",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_explosiveness"),_SCS("get_explosiveness")); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL,"config/flip_h"),_SCS("set_flip_h"),_SCS("is_flipped_h")); + ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL,"config/flip_v"),_SCS("set_flip_v"),_SCS("is_flipped_v")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"config/texture",PROPERTY_HINT_RESOURCE_TYPE,"Texture"),_SCS("set_texture"),_SCS("get_texture")); + ADD_PROPERTYNO(PropertyInfo(Variant::INT,"config/h_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_h_frames"),_SCS("get_h_frames")); + ADD_PROPERTYNO(PropertyInfo(Variant::INT,"config/v_frames",PROPERTY_HINT_RANGE,"1,512,1"),_SCS("set_v_frames"),_SCS("get_v_frames")); for(int i=0;i<PARAM_MAX;i++) { @@ -1092,10 +1092,10 @@ void Particles2D::_bind_methods() { } for(int i=0;i<PARAM_MAX;i++) { - ADD_PROPERTYI(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i); + ADD_PROPERTYINZ(PropertyInfo(Variant::REAL,_particlesframe_property_rnames[i],PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_randomness"),_SCS("get_randomness"),i); } - ADD_PROPERTY( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1", 0), _SCS("set_color_phases"), _SCS("get_color_phases")); + ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "color_phases/count",PROPERTY_HINT_RANGE,"0,4,1", 0), _SCS("set_color_phases"), _SCS("get_color_phases")); //Backward compatibility. They will be converted to color ramp for(int i=0;i<MAX_COLOR_PHASES;i++) { @@ -1104,10 +1104,10 @@ void Particles2D::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::COLOR, phase+"color", PROPERTY_HINT_NONE, "", 0),_SCS("set_color_phase_color"),_SCS("get_color_phase_color"),i ); } - ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color/color"),_SCS("set_color"),_SCS("get_color")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"color/color_ramp",PROPERTY_HINT_RESOURCE_TYPE,"ColorRamp"),_SCS("set_color_ramp"),_SCS("get_color_ramp")); + ADD_PROPERTYNO(PropertyInfo(Variant::COLOR, "color/color"),_SCS("set_color"),_SCS("get_color")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"color/color_ramp",PROPERTY_HINT_RESOURCE_TYPE,"ColorRamp"),_SCS("set_color_ramp"),_SCS("get_color_ramp")); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points")); + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2_ARRAY,"emission_points",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_emission_points"),_SCS("get_emission_points")); BIND_CONSTANT( PARAM_DIRECTION ); BIND_CONSTANT( PARAM_SPREAD ); diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 20abe42cd9..acc4c620e6 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -53,6 +53,16 @@ uint32_t RayCast2D::get_layer_mask() const { return layer_mask; } +void RayCast2D::set_type_mask(uint32_t p_mask) { + + type_mask=p_mask; +} + +uint32_t RayCast2D::get_type_mask() const { + + return type_mask; +} + bool RayCast2D::is_colliding() const{ return collided; @@ -115,17 +125,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 +149,7 @@ void RayCast2D::_notification(int p_what) { draw_primitive(pts,cols,Vector<Vector2>()); //small arrow } break; -#endif + case NOTIFICATION_FIXED_PROCESS: { @@ -162,7 +172,7 @@ void RayCast2D::_notification(int p_what) { Physics2DDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask)) { + if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude,layer_mask,type_mask)) { collided=true; against=rr.collider_id; @@ -241,9 +251,13 @@ void RayCast2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&RayCast2D::set_layer_mask); ObjectTypeDB::bind_method(_MD("get_layer_mask"),&RayCast2D::get_layer_mask); + ObjectTypeDB::bind_method(_MD("set_type_mask","mask"),&RayCast2D::set_type_mask); + ObjectTypeDB::bind_method(_MD("get_type_mask"),&RayCast2D::get_type_mask); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to")); ADD_PROPERTY(PropertyInfo(Variant::INT,"layer_mask",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); + ADD_PROPERTY(PropertyInfo(Variant::INT,"type_mask",PROPERTY_HINT_FLAGS,"Static,Kinematic,Rigid,Character,Area"),_SCS("set_type_mask"),_SCS("get_type_mask")); } RayCast2D::RayCast2D() { @@ -253,5 +267,6 @@ RayCast2D::RayCast2D() { collided=false; against_shape=0; layer_mask=1; + type_mask=Physics2DDirectSpaceState::TYPE_MASK_COLLISION; cast_to=Vector2(0,50); } diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h index c7616be523..8c3ce8b3b3 100644 --- a/scene/2d/ray_cast_2d.h +++ b/scene/2d/ray_cast_2d.h @@ -44,6 +44,7 @@ class RayCast2D : public Node2D { Vector2 collision_normal; Set<RID> exclude; uint32_t layer_mask; + uint32_t type_mask; Vector2 cast_to; @@ -62,6 +63,9 @@ public: void set_layer_mask(uint32_t p_mask); uint32_t get_layer_mask() const; + void set_type_mask(uint32_t p_mask); + uint32_t get_type_mask() const; + bool is_colliding() const; Object *get_collider() const; int get_collider_shape() const; 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 067b4794b4..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) { @@ -82,9 +83,12 @@ void Sprite::_notification(int p_what) { } - Point2i ofs=offset; + Point2 ofs=offset; if (centered) ofs-=s/2; + if (OS::get_singleton()->get_use_pixel_snap()) { + ofs=ofs.floor(); + } Rect2 dst_rect(ofs,s); @@ -103,14 +107,18 @@ void Sprite::set_texture(const Ref<Texture>& p_texture) { if (p_texture==texture) return; +#ifdef DEBUG_ENABLED if (texture.is_valid()) { texture->disconnect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update); } +#endif texture=p_texture; +#ifdef DEBUG_ENABLED if (texture.is_valid()) { texture->set_flags(texture->get_flags()); //remove repeat from texture, it looks bad in sprites texture->connect(CoreStringNames::get_singleton()->changed,this,SceneStringNames::get_singleton()->update); } +#endif update(); item_rect_changed(); } @@ -185,6 +193,7 @@ void Sprite::set_region_rect(const Rect2& p_region_rect) { if (region && changed) { update(); item_rect_changed(); + _change_notify("region_rect"); } } @@ -265,7 +274,7 @@ Rect2 Sprite::get_item_rect() const { s=s/Point2(hframes,vframes); } - Point2i ofs=offset; + Point2 ofs=offset; if (centered) ofs-=s/2; @@ -313,17 +322,17 @@ void Sprite::_bind_methods() { ADD_SIGNAL(MethodInfo("frame_changed")); - ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); - ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); - ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); - ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); + ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); + ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_h"), _SCS("set_flip_h"),_SCS("is_flipped_h")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "flip_v"), _SCS("set_flip_v"),_SCS("is_flipped_v")); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes")); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes")); + ADD_PROPERTYNZ( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); + ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); + ADD_PROPERTYNZ( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); } @@ -413,11 +422,14 @@ void ViewportSprite::_notification(int p_what) { src_rect.size=s; - Point2i ofs=offset; + Point2 ofs=offset; if (centered) ofs-=s/2; - Rect2i dst_rect(ofs,s); + 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); } break; @@ -505,7 +517,7 @@ Rect2 ViewportSprite::get_item_rect() const { Size2i s; s = texture->get_size(); - Point2i ofs=offset; + Point2 ofs=offset; if (centered) ofs-=s/2; @@ -530,10 +542,10 @@ void ViewportSprite::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&ViewportSprite::set_modulate); ObjectTypeDB::bind_method(_MD("get_modulate"),&ViewportSprite::get_modulate); - ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); - ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); - ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); + ADD_PROPERTYNZ( PropertyInfo( Variant::NODE_PATH, "viewport"), _SCS("set_viewport_path"),_SCS("get_viewport_path")); + ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); + ADD_PROPERTYNZ( PropertyInfo( Variant::VECTOR2, "offset"), _SCS("set_offset"),_SCS("get_offset")); + ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate")); } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 2fca1e67e8..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; @@ -579,6 +597,10 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) { call_deferred("_update_dirty_quadrants"); } +void TileMap::set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) { + + set_cell(p_pos.x,p_pos.y,p_tile,p_flip_x,p_flip_y,p_transpose); +} void TileMap::set_cell(int p_x,int p_y,int p_tile,bool p_flip_x,bool p_flip_y,bool p_transpose) { @@ -1106,6 +1128,7 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_bounce"),&TileMap::get_collision_bounce); ObjectTypeDB::bind_method(_MD("set_cell","x","y","tile","flip_x","flip_y","transpose"),&TileMap::set_cell,DEFVAL(false),DEFVAL(false),DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("set_cellv","pos","tile","flip_x","flip_y","transpose"),&TileMap::set_cellv,DEFVAL(false),DEFVAL(false),DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_cell","x","y"),&TileMap::get_cell); ObjectTypeDB::bind_method(_MD("is_cell_x_flipped","x","y"),&TileMap::is_cell_x_flipped); ObjectTypeDB::bind_method(_MD("is_cell_y_flipped","x","y"),&TileMap::is_cell_y_flipped); diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index 84ca65da4f..60534cce15 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -207,6 +207,8 @@ public: bool is_cell_y_flipped(int p_x,int p_y) const; bool is_cell_transposed(int p_x,int p_y) const; + void set_cellv(const Vector2& p_pos,int p_tile,bool p_flip_x=false,bool p_flip_y=false,bool p_transpose=false); + Rect2 get_item_rect() const; void set_collision_layer(uint32_t p_layer); diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index ea4b1fc7b0..dc72c9a267 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -155,6 +155,11 @@ void VisibilityEnabler2D::_screen_enter() { _change_node_state(E->key(),true); } + if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent()) + get_parent()->set_fixed_process(true); + if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) + get_parent()->set_process(true); + visible=true; } @@ -165,6 +170,11 @@ void VisibilityEnabler2D::_screen_exit(){ _change_node_state(E->key(),false); } + if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent()) + get_parent()->set_fixed_process(false); + if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) + get_parent()->set_process(false); + visible=false; } @@ -235,6 +245,12 @@ void VisibilityEnabler2D::_notification(int p_what){ _find_nodes(from); + if (enabler[ENABLER_PARENT_FIXED_PROCESS] && get_parent()) + get_parent()->set_fixed_process(false); + if (enabler[ENABLER_PARENT_PROCESS] && get_parent()) + get_parent()->set_process(false); + + } if (p_what==NOTIFICATION_EXIT_TREE) { @@ -317,10 +333,14 @@ void VisibilityEnabler2D::_bind_methods(){ ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_animations"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_ANIMATIONS ); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/freeze_bodies"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_FREEZE_BODIES); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/pause_particles"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PAUSE_PARTICLES); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/process_parent"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PARENT_PROCESS); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"enabler/fixed_process_parent"),_SCS("set_enabler"),_SCS("is_enabler_enabled"), ENABLER_PARENT_FIXED_PROCESS); BIND_CONSTANT( ENABLER_FREEZE_BODIES ); BIND_CONSTANT( ENABLER_PAUSE_ANIMATIONS ); BIND_CONSTANT( ENABLER_PAUSE_PARTICLES ); + BIND_CONSTANT( ENABLER_PARENT_PROCESS ); + BIND_CONSTANT( ENABLER_PARENT_FIXED_PROCESS ); BIND_CONSTANT( ENABLER_MAX); } @@ -341,6 +361,8 @@ VisibilityEnabler2D::VisibilityEnabler2D() { for(int i=0;i<ENABLER_MAX;i++) enabler[i]=true; + enabler[ENABLER_PARENT_PROCESS]=false; + enabler[ENABLER_PARENT_FIXED_PROCESS]=false; visible=false; diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h index ce68724630..1f7e4c6d45 100644 --- a/scene/2d/visibility_notifier_2d.h +++ b/scene/2d/visibility_notifier_2d.h @@ -74,6 +74,8 @@ public: ENABLER_PAUSE_ANIMATIONS, ENABLER_FREEZE_BODIES, ENABLER_PAUSE_PARTICLES, + ENABLER_PARENT_PROCESS, + ENABLER_PARENT_FIXED_PROCESS, ENABLER_MAX }; diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index 76527c72e6..ff35837bc0 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -83,15 +83,25 @@ real_t Area::get_gravity() const{ return gravity; } +void Area::set_linear_damp(real_t p_linear_damp){ -void Area::set_density(real_t p_density){ + linear_damp=p_linear_damp; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_LINEAR_DAMP,p_linear_damp); +} +real_t Area::get_linear_damp() const{ - density=p_density; - PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_DENSITY,p_density); + return linear_damp; } -real_t Area::get_density() const{ - return density; +void Area::set_angular_damp(real_t p_angular_damp){ + + angular_damp=p_angular_damp; + PhysicsServer::get_singleton()->area_set_param(get_rid(),PhysicsServer::AREA_PARAM_ANGULAR_DAMP,p_angular_damp); +} + +real_t Area::get_angular_damp() const{ + + return angular_damp; } void Area::set_priority(real_t p_priority){ @@ -225,27 +235,56 @@ void Area::_clear_monitoring() { } ERR_FAIL_COND(locked); - Map<ObjectID,BodyState> bmcopy = body_map; - body_map.clear(); - //disconnect all monitored stuff + { + Map<ObjectID,BodyState> bmcopy = body_map; + body_map.clear(); + //disconnect all monitored stuff - for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) { + for (Map<ObjectID,BodyState>::Element *E=bmcopy.front();E;E=E->next()) { - Object *obj = ObjectDB::get_instance(E->key()); - Node *node = obj ? obj->cast_to<Node>() : NULL; - ERR_CONTINUE(!node); - if (!E->get().in_tree) - continue; + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_CONTINUE(!node); + if (!E->get().in_tree) + continue; + + for(int i=0;i<E->get().shapes.size();i++) { - for(int i=0;i<E->get().shapes.size();i++) { + emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + } - emit_signal(SceneStringNames::get_singleton()->body_exit_shape,E->key(),node,E->get().shapes[i].body_shape,E->get().shapes[i].area_shape); + emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + + node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree); + node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree); } - emit_signal(SceneStringNames::get_singleton()->body_exit,obj); + } + + { + + Map<ObjectID,AreaState> bmcopy = area_map; + area_map.clear(); + //disconnect all monitored stuff + + for (Map<ObjectID,AreaState>::Element *E=bmcopy.front();E;E=E->next()) { + + Object *obj = ObjectDB::get_instance(E->key()); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_CONTINUE(!node); + if (!E->get().in_tree) + continue; + + for(int i=0;i<E->get().shapes.size();i++) { - node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree); - node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree); + emit_signal(SceneStringNames::get_singleton()->area_exit_shape,E->key(),node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape); + } + + emit_signal(SceneStringNames::get_singleton()->area_exit,obj); + + node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree); + node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree); + } } } @@ -270,13 +309,130 @@ void Area::set_enable_monitoring(bool p_enable) { if (monitoring) { - PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,"_body_inout"); + PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_body_inout); + PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),this,SceneStringNames::get_singleton()->_area_inout); } else { PhysicsServer::get_singleton()->area_set_monitor_callback(get_rid(),NULL,StringName()); + PhysicsServer::get_singleton()->area_set_area_monitor_callback(get_rid(),NULL,StringName()); _clear_monitoring(); + } } + +void Area::_area_enter_tree(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + + Map<ObjectID,AreaState>::Element *E=area_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(E->get().in_tree); + + E->get().in_tree=true; + emit_signal(SceneStringNames::get_singleton()->area_enter,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->area_enter_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape); + } + +} + +void Area::_area_exit_tree(ObjectID p_id) { + + Object *obj = ObjectDB::get_instance(p_id); + Node *node = obj ? obj->cast_to<Node>() : NULL; + ERR_FAIL_COND(!node); + Map<ObjectID,AreaState>::Element *E=area_map.find(p_id); + ERR_FAIL_COND(!E); + ERR_FAIL_COND(!E->get().in_tree); + E->get().in_tree=false; + emit_signal(SceneStringNames::get_singleton()->area_exit,node); + for(int i=0;i<E->get().shapes.size();i++) { + + emit_signal(SceneStringNames::get_singleton()->area_exit_shape,p_id,node,E->get().shapes[i].area_shape,E->get().shapes[i].self_shape); + } + +} + +void Area::_area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape) { + + + bool area_in = p_status==PhysicsServer::AREA_BODY_ADDED; + ObjectID objid=p_instance; + + Object *obj = ObjectDB::get_instance(objid); + Node *node = obj ? obj->cast_to<Node>() : NULL; + + Map<ObjectID,AreaState>::Element *E=area_map.find(objid); + + ERR_FAIL_COND(!area_in && !E); + + locked=true; + + if (area_in) { + if (!E) { + + E = area_map.insert(objid,AreaState()); + E->get().rc=0; + E->get().in_tree=node && node->is_inside_tree(); + if (node) { + node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree,make_binds(objid)); + if (E->get().in_tree) { + emit_signal(SceneStringNames::get_singleton()->area_enter,node); + + } + } + + } + E->get().rc++; + if (node) + E->get().shapes.insert(AreaShapePair(p_area_shape,p_self_shape)); + + + if (!node || E->get().in_tree) { + emit_signal(SceneStringNames::get_singleton()->area_enter_shape,objid,node,p_area_shape,p_self_shape); + } + + } else { + + E->get().rc--; + + if (node) + E->get().shapes.erase(AreaShapePair(p_area_shape,p_self_shape)); + + bool eraseit=false; + + if (E->get().rc==0) { + + if (node) { + node->disconnect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_area_enter_tree); + node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_area_exit_tree); + if (E->get().in_tree) { + emit_signal(SceneStringNames::get_singleton()->area_exit,obj); + } + + } + + eraseit=true; + + } + if (!node || E->get().in_tree) { + emit_signal(SceneStringNames::get_singleton()->area_exit_shape,objid,obj,p_area_shape,p_self_shape); + } + + if (eraseit) + area_map.erase(E); + + } + + locked=false; + + +} + bool Area::is_monitoring_enabled() const { return monitoring; @@ -302,11 +458,76 @@ Array Area::get_overlapping_bodies() const { return ret; } +void Area::set_monitorable(bool p_enable) { + + if (locked) { + ERR_EXPLAIN("This function can't be used during the in/out signal."); + } + ERR_FAIL_COND(locked); + + if (p_enable==monitorable) + return; + + monitorable=p_enable; + + PhysicsServer::get_singleton()->area_set_monitorable(get_rid(),monitorable); +} + +bool Area::is_monitorable() const { + + return monitorable; +} + + +Array Area::get_overlapping_areas() const { + + ERR_FAIL_COND_V(!monitoring,Array()); + Array ret; + ret.resize(area_map.size()); + int idx=0; + for (const Map<ObjectID,AreaState>::Element *E=area_map.front();E;E=E->next()) { + Object *obj = ObjectDB::get_instance(E->key()); + if (!obj) { + ret.resize( ret.size() -1 ); //ops + } else { + ret[idx++]=obj; + } + + } + + return ret; +} + +bool Area::overlaps_area(Node* p_area) const { + + ERR_FAIL_NULL_V(p_area,false); + const Map<ObjectID,AreaState>::Element *E=area_map.find(p_area->get_instance_ID()); + if (!E) + return false; + return E->get().in_tree; + + + +} + +bool Area::overlaps_body(Node* p_body) const{ + + ERR_FAIL_NULL_V(p_body,false); + const Map<ObjectID,BodyState>::Element *E=body_map.find(p_body->get_instance_ID()); + if (!E) + return false; + return E->get().in_tree; + +} + void Area::_bind_methods() { ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area::_body_enter_tree); ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area::_body_exit_tree); + ObjectTypeDB::bind_method(_MD("_area_enter_tree","id"),&Area::_area_enter_tree); + ObjectTypeDB::bind_method(_MD("_area_exit_tree","id"),&Area::_area_exit_tree); + ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area::set_space_override_mode); ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area::get_space_override_mode); @@ -322,19 +543,30 @@ void Area::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area::set_gravity); ObjectTypeDB::bind_method(_MD("get_gravity"),&Area::get_gravity); - ObjectTypeDB::bind_method(_MD("set_density","density"),&Area::set_density); - ObjectTypeDB::bind_method(_MD("get_density"),&Area::get_density); + ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&Area::set_angular_damp); + ObjectTypeDB::bind_method(_MD("get_angular_damp"),&Area::get_angular_damp); + + ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&Area::set_linear_damp); + ObjectTypeDB::bind_method(_MD("get_linear_damp"),&Area::get_linear_damp); ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority); ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority); + ObjectTypeDB::bind_method(_MD("set_monitorable","enable"),&Area::set_monitorable); + ObjectTypeDB::bind_method(_MD("is_monitorable"),&Area::is_monitorable); + ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area::set_enable_monitoring); ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area::is_monitoring_enabled); ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area::get_overlapping_bodies); + ObjectTypeDB::bind_method(_MD("get_overlapping_areas"),&Area::get_overlapping_areas); + + ObjectTypeDB::bind_method(_MD("overlaps_body:PhysicsBody","body"),&Area::overlaps_body); + ObjectTypeDB::bind_method(_MD("overlaps_area:Area","area"),&Area::overlaps_area); ObjectTypeDB::bind_method(_MD("_body_inout"),&Area::_body_inout); + ObjectTypeDB::bind_method(_MD("_area_inout"),&Area::_area_inout); ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"area_shape"))); @@ -342,14 +574,21 @@ void Area::_bind_methods() { ADD_SIGNAL( MethodInfo("body_enter",PropertyInfo(Variant::OBJECT,"body"))); ADD_SIGNAL( MethodInfo("body_exit",PropertyInfo(Variant::OBJECT,"body"))); + ADD_SIGNAL( MethodInfo("area_enter_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("area_exit_shape",PropertyInfo(Variant::INT,"area_id"),PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"),PropertyInfo(Variant::INT,"area_shape"),PropertyInfo(Variant::INT,"area_shape"))); + ADD_SIGNAL( MethodInfo("area_enter",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"))); + ADD_SIGNAL( MethodInfo("area_exit",PropertyInfo(Variant::OBJECT,"area",PROPERTY_HINT_RESOURCE_TYPE,"Area"))); + ADD_PROPERTY( PropertyInfo(Variant::INT,"space_override",PROPERTY_HINT_ENUM,"Disabled,Combine,Replace"),_SCS("set_space_override_mode"),_SCS("get_space_override_mode")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_distance_scale", PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_gravity_distance_scale"),_SCS("get_gravity_distance_scale")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"gravity_vec"),_SCS("set_gravity_vector"),_SCS("get_gravity_vector")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity",PROPERTY_HINT_RANGE,"-1024,1024,0.01"),_SCS("set_gravity"),_SCS("get_gravity")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"linear_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"angular_damp",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); ADD_PROPERTY( PropertyInfo(Variant::INT,"priority",PROPERTY_HINT_RANGE,"0,128,1"),_SCS("set_priority"),_SCS("get_priority")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitoring"),_SCS("set_enable_monitoring"),_SCS("is_monitoring_enabled")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"monitorable"),_SCS("set_monitorable"),_SCS("is_monitorable")); } @@ -361,11 +600,13 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru set_gravity_vector(Vector3(0,-1,0)); gravity_is_point=false; gravity_distance_scale=0; - density=0.1; + linear_damp=0.1; + angular_damp=1; priority=0; monitoring=false; set_ray_pickable(false); set_enable_monitoring(true); + set_monitorable(true); } diff --git a/scene/3d/area.h b/scene/3d/area.h index fb853092f3..f03955d1e7 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -50,9 +50,11 @@ private: real_t gravity; bool gravity_is_point; real_t gravity_distance_scale; - real_t density; + real_t angular_damp; + real_t linear_damp; int priority; bool monitoring; + bool monitorable; bool locked; @@ -84,6 +86,36 @@ private: }; Map<ObjectID,BodyState> body_map; + + + void _area_inout(int p_status,const RID& p_area, int p_instance, int p_area_shape,int p_self_shape); + + void _area_enter_tree(ObjectID p_id); + void _area_exit_tree(ObjectID p_id); + + struct AreaShapePair { + + int area_shape; + int self_shape; + bool operator<(const AreaShapePair& p_sp) const { + if (area_shape==p_sp.area_shape) + return self_shape < p_sp.self_shape; + else + return area_shape < p_sp.area_shape; + } + + AreaShapePair() {} + AreaShapePair(int p_bs, int p_as) { area_shape=p_bs; self_shape=p_as; } + }; + + struct AreaState { + + int rc; + bool in_tree; + VSet<AreaShapePair> shapes; + }; + + Map<ObjectID,AreaState> area_map; void _clear_monitoring(); @@ -108,8 +140,11 @@ public: void set_gravity(real_t p_gravity); real_t get_gravity() const; - void set_density(real_t p_density); - real_t get_density() const; + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; void set_priority(real_t p_priority); real_t get_priority() const; @@ -117,7 +152,14 @@ public: void set_enable_monitoring(bool p_enable); bool is_monitoring_enabled() const; + void set_monitorable(bool p_enable); + bool is_monitorable() const; + Array get_overlapping_bodies() const; + Array get_overlapping_areas() const; //function for script + + bool overlaps_area(Node* p_area) const; + bool overlaps_body(Node* p_body) const; Area(); 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_object.cpp b/scene/3d/collision_object.cpp index efc5db50e1..5ecadb48b8 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -122,8 +122,8 @@ bool CollisionObject::_set(const StringName& p_name, const Variant& p_value) { } else if (name.begins_with("shapes/")) { - int idx=name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int idx=name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="shape") set_shape(idx,RefPtr(p_value)); else if (what=="transform") @@ -148,8 +148,8 @@ bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const { r_ret= shapes.size(); } else if (name.begins_with("shapes/")) { - int idx=name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int idx=name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (what=="shape") r_ret= get_shape(idx); else if (what=="transform") 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/physics_body.cpp b/scene/3d/physics_body.cpp index 3d5091f667..d61859a3d0 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -133,6 +133,8 @@ real_t StaticBody::get_bounce() const{ return bounce; } + + void StaticBody::set_constant_linear_velocity(const Vector3& p_vel) { constant_linear_velocity=p_vel; @@ -494,6 +496,42 @@ real_t RigidBody::get_bounce() const{ return bounce; } + +void RigidBody::set_gravity_scale(real_t p_gravity_scale){ + + gravity_scale=p_gravity_scale; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_GRAVITY_SCALE,gravity_scale); + +} +real_t RigidBody::get_gravity_scale() const{ + + return gravity_scale; +} + +void RigidBody::set_linear_damp(real_t p_linear_damp){ + + ERR_FAIL_COND(p_linear_damp<-1); + linear_damp=p_linear_damp; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_LINEAR_DAMP,linear_damp); + +} +real_t RigidBody::get_linear_damp() const{ + + return linear_damp; +} + +void RigidBody::set_angular_damp(real_t p_angular_damp){ + + ERR_FAIL_COND(p_angular_damp<-1); + angular_damp=p_angular_damp; + PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_ANGULAR_DAMP,angular_damp); + +} +real_t RigidBody::get_angular_damp() const{ + + return angular_damp; +} + void RigidBody::set_axis_velocity(const Vector3& p_axis) { Vector3 v = state? state->get_linear_velocity() : linear_velocity; @@ -685,6 +723,16 @@ void RigidBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_angular_velocity","angular_velocity"),&RigidBody::set_angular_velocity); ObjectTypeDB::bind_method(_MD("get_angular_velocity"),&RigidBody::get_angular_velocity); + ObjectTypeDB::bind_method(_MD("set_gravity_scale","gravity_scale"),&RigidBody::set_gravity_scale); + ObjectTypeDB::bind_method(_MD("get_gravity_scale"),&RigidBody::get_gravity_scale); + + ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&RigidBody::set_linear_damp); + ObjectTypeDB::bind_method(_MD("get_linear_damp"),&RigidBody::get_linear_damp); + + ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&RigidBody::set_angular_damp); + ObjectTypeDB::bind_method(_MD("get_angular_damp"),&RigidBody::get_angular_damp); + + ObjectTypeDB::bind_method(_MD("set_max_contacts_reported","amount"),&RigidBody::set_max_contacts_reported); ObjectTypeDB::bind_method(_MD("get_max_contacts_reported"),&RigidBody::get_max_contacts_reported); @@ -722,6 +770,7 @@ void RigidBody::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL,"weight",PROPERTY_HINT_EXP_RANGE,"0.01,65535,0.01",PROPERTY_USAGE_EDITOR),_SCS("set_weight"),_SCS("get_weight")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_bounce"),_SCS("get_bounce")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"gravity_scale",PROPERTY_HINT_RANGE,"-128,128,0.01"),_SCS("set_gravity_scale"),_SCS("get_gravity_scale")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"custom_integrator"),_SCS("set_use_custom_integrator"),_SCS("is_using_custom_integrator")); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"continuous_cd"),_SCS("set_use_continuous_collision_detection"),_SCS("is_using_continuous_collision_detection")); ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported")); @@ -731,6 +780,8 @@ void RigidBody::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::INT,"axis_lock",PROPERTY_HINT_ENUM,"Disabled,Lock X,Lock Y,Lock Z"),_SCS("set_axis_lock"),_SCS("get_axis_lock")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"velocity/angular"),_SCS("set_angular_velocity"),_SCS("get_angular_velocity")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/linear",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_linear_damp"),_SCS("get_linear_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"damp_override/angular",PROPERTY_HINT_RANGE,"-1,128,0.01"),_SCS("set_angular_damp"),_SCS("get_angular_damp")); ADD_SIGNAL( MethodInfo("body_enter_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); ADD_SIGNAL( MethodInfo("body_exit_shape",PropertyInfo(Variant::INT,"body_id"),PropertyInfo(Variant::OBJECT,"body"),PropertyInfo(Variant::INT,"body_shape"),PropertyInfo(Variant::INT,"local_shape"))); @@ -753,6 +804,10 @@ RigidBody::RigidBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) { max_contacts_reported=0; state=NULL; + gravity_scale=1; + linear_damp=-1; + angular_damp=-1; + //angular_velocity=0; sleeping=false; ccd=false; diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 0ff3b360af..66490ba925 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -129,6 +129,10 @@ private: Vector3 linear_velocity; Vector3 angular_velocity; + real_t gravity_scale; + real_t linear_damp; + real_t angular_damp; + bool sleeping; bool ccd; @@ -217,6 +221,16 @@ public: void set_angular_velocity(const Vector3&p_velocity); Vector3 get_angular_velocity() const; + void set_gravity_scale(real_t p_gravity_scale); + real_t get_gravity_scale() const; + + void set_linear_damp(real_t p_linear_damp); + real_t get_linear_damp() const; + + void set_angular_damp(real_t p_angular_damp); + real_t get_angular_damp() const; + + void set_use_custom_integrator(bool p_enable); bool is_using_custom_integrator(); diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index ee1b28a8ae..4712ba308a 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -41,8 +41,8 @@ bool Skeleton::_set(const StringName& p_path, const Variant& p_value) { if (!path.begins_with("bones/")) return false; - int which=path.get_slice("/",1).to_int(); - String what=path.get_slice("/",2); + int which=path.get_slicec('/',1).to_int(); + String what=path.get_slicec('/',2); if (which==bones.size() && what=="name") { @@ -88,8 +88,8 @@ bool Skeleton::_get(const StringName& p_name,Variant &r_ret) const { if (!path.begins_with("bones/")) return false; - int which=path.get_slice("/",1).to_int(); - String what=path.get_slice("/",2); + int which=path.get_slicec('/',1).to_int(); + String what=path.get_slicec('/',2); ERR_FAIL_INDEX_V( which, bones.size(), false ); @@ -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 c672d0e94f..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); @@ -758,7 +782,7 @@ void Spatial::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("_set_rotation_deg"), _SCS("_get_rotation_deg") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/rotation_rad",PROPERTY_HINT_NONE,"",0), _SCS("set_rotation"), _SCS("get_rotation") ); ADD_PROPERTY( PropertyInfo(Variant::VECTOR3,"transform/scale",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_EDITOR), _SCS("set_scale"), _SCS("get_scale") ); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") ); + ADD_PROPERTYNO( PropertyInfo(Variant::BOOL,"visibility/visible"), _SCS("_set_visible_"), _SCS("_is_visible_") ); //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), _SCS("set_transform"), _SCS("get_transform") ); ADD_SIGNAL( MethodInfo("visibility_changed" ) ); @@ -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/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index e9da95f3fb..c7d1249a07 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -578,8 +578,8 @@ void Sprite3D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_hframes"),&Sprite3D::get_hframes); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_texture"),_SCS("get_texture")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes"), _SCS("set_vframes"),_SCS("get_vframes")); - ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes"), _SCS("set_hframes"),_SCS("get_hframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "vframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_vframes"),_SCS("get_vframes")); + ADD_PROPERTY( PropertyInfo( Variant::INT, "hframes",PROPERTY_HINT_RANGE,"1,16384,1"), _SCS("set_hframes"),_SCS("get_hframes")); ADD_PROPERTY( PropertyInfo( Variant::INT, "frame",PROPERTY_HINT_SPRITE_FRAME), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "region"), _SCS("set_region"),_SCS("is_region")); ADD_PROPERTY( PropertyInfo( Variant::RECT2, "region_rect"), _SCS("set_region_rect"),_SCS("get_region_rect")); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 74ae2c0d55..c2ea1c8bb6 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -35,10 +35,10 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) { String name=p_name; - if (name=="playback/speed" || name=="speed") { //bw compatibility + if (p_name==SceneStringNames::get_singleton()->playback_speed || p_name==SceneStringNames::get_singleton()->speed) { //bw compatibility set_speed(p_value); - } else if (name=="playback/active") { + } else if (p_name==SceneStringNames::get_singleton()->playback_active) { set_active(p_value); } else if (name.begins_with("playback/play")) { @@ -52,16 +52,16 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) { } else if (name.begins_with("anims/")) { - String which=name.get_slice("/",1); + String which=name.get_slicec('/',1); add_animation(which,p_value); } else if (name.begins_with("next/")) { - String which=name.get_slice("/",1); + String which=name.get_slicec('/',1); animation_set_next(which,p_value); - } else if (name=="blend_times") { + } else if (p_name==SceneStringNames::get_singleton()->blend_times) { Array array=p_value; int len = array.size(); @@ -77,7 +77,7 @@ bool AnimationPlayer::_set(const StringName& p_name, const Variant& p_value) { set_blend_time(from,to,time); } - } else if (name=="autoplay") { + } else if (p_name==SceneStringNames::get_singleton()->autoplay) { autoplay=p_value; } else @@ -106,12 +106,12 @@ bool AnimationPlayer::_get(const StringName& p_name,Variant &r_ret) const { } else if (name.begins_with("anims/")) { - String which=name.get_slice("/",1); + String which=name.get_slicec('/',1); r_ret= get_animation(which).get_ref_ptr(); } else if (name.begins_with("next/")) { - String which=name.get_slice("/",1); + String which=name.get_slicec('/',1); r_ret= animation_get_next(which); @@ -661,8 +661,11 @@ void AnimationPlayer::_animation_process(float p_delta) { Error AnimationPlayer::add_animation(const StringName& p_name, const Ref<Animation>& p_animation) { +#ifdef DEBUG_ENABLED ERR_EXPLAIN("Invalid animation name: "+String(p_name)); ERR_FAIL_COND_V( String(p_name).find("/")!=-1 || String(p_name).find(":")!=-1 || String(p_name).find(",")!=-1 || String(p_name).find("[")!=-1, ERR_INVALID_PARAMETER ); +#endif + ERR_FAIL_COND_V( p_animation.is_null() , ERR_INVALID_PARAMETER ); //print_line("Add anim: "+String(p_name)+" name: "+p_animation->get_name()); @@ -854,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()); @@ -1213,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); @@ -1271,7 +1280,7 @@ AnimationPlayer::AnimationPlayer() { animation_process_mode=ANIMATION_PROCESS_IDLE; processing=false; default_blend_time=0; - root=NodePath(".."); + root=SceneStringNames::get_singleton()->path_pp; playing = false; active=true; } 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 25e83df39d..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_slice("/",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 8b6f433c9c..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() { @@ -390,10 +400,10 @@ void BaseButton::_bind_methods() { ADD_SIGNAL( MethodInfo("pressed" ) ); ADD_SIGNAL( MethodInfo("released" ) ); ADD_SIGNAL( MethodInfo("toggled", PropertyInfo( Variant::BOOL,"pressed") ) ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "disabled"), _SCS("set_disabled"), _SCS("is_disabled")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "is_pressed"), _SCS("set_pressed"), _SCS("is_pressed")); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press")); BIND_CONSTANT( DRAW_NORMAL ); 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/button.cpp b/scene/gui/button.cpp index b465db5c80..edeb18bfc1 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -225,11 +225,11 @@ void Button::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_text_align"),&Button::get_text_align); ObjectTypeDB::bind_method(_MD("is_flat"),&Button::is_flat); - ADD_PROPERTY( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") ); - ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text", PROPERTY_HINT_NONE,"",PROPERTY_USAGE_DEFAULT_INTL ), _SCS("set_text"),_SCS("get_text") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), _SCS("set_button_icon"),_SCS("get_button_icon") ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "flat" ), _SCS("set_flat"),_SCS("is_flat") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "clip_text" ), _SCS("set_clip_text"),_SCS("get_clip_text") ); - ADD_PROPERTY( PropertyInfo( Variant::INT, "align",PROPERTY_HINT_ENUM,"Left,Center,Right" ), _SCS("set_text_align"),_SCS("get_text_align") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "clip_text" ), _SCS("set_clip_text"),_SCS("get_clip_text") ); + ADD_PROPERTYNO( PropertyInfo( Variant::INT, "align",PROPERTY_HINT_ENUM,"Left,Center,Right" ), _SCS("set_text_align"),_SCS("get_text_align") ); } diff --git a/scene/gui/button_array.cpp b/scene/gui/button_array.cpp index 7f565de244..b86e32dda7 100644 --- a/scene/gui/button_array.cpp +++ b/scene/gui/button_array.cpp @@ -34,7 +34,7 @@ bool ButtonArray::_set(const StringName& p_name, const Variant& p_value) { String n=String(p_name); if (n.begins_with("button/")) { - String what = n.get_slice("/",1); + String what = n.get_slicec('/',1); if (what=="count") { int new_size=p_value; if (new_size>0 && buttons.size()==0) { @@ -57,7 +57,7 @@ bool ButtonArray::_set(const StringName& p_name, const Variant& p_value) { } else { int idx=what.to_int(); ERR_FAIL_INDEX_V(idx,buttons.size(),false); - String f = n.get_slice("/",2); + String f = n.get_slicec('/',2); if (f=="text") buttons[idx].text=p_value; else if (f=="icon") @@ -80,7 +80,7 @@ bool ButtonArray::_get(const StringName& p_name,Variant &r_ret) const { String n=String(p_name); if (n.begins_with("button/")) { - String what = n.get_slice("/",1); + String what = n.get_slicec('/',1); if (what=="count") { r_ret=buttons.size(); } else if (what=="align") { @@ -92,7 +92,7 @@ bool ButtonArray::_get(const StringName& p_name,Variant &r_ret) const { } else { int idx=what.to_int(); ERR_FAIL_INDEX_V(idx,buttons.size(),false); - String f = n.get_slice("/",2); + String f = n.get_slicec('/',2); if (f=="text") r_ret=buttons[idx].text; else if (f=="icon") diff --git a/scene/gui/color_ramp_edit.cpp b/scene/gui/color_ramp_edit.cpp index 382c0dc103..14a48fe3d3 100644 --- a/scene/gui/color_ramp_edit.cpp +++ b/scene/gui/color_ramp_edit.cpp @@ -48,6 +48,7 @@ void ColorRampEdit::_input_event(const InputEvent& p_event) { points.remove(grabbed); grabbed=-1; + grabbing=false; update(); emit_signal("ramp_changed"); accept_event(); @@ -67,12 +68,38 @@ void ColorRampEdit::_input_event(const InputEvent& p_event) { { points.remove(grabbed); grabbed=-1; + grabbing=false; update(); emit_signal("ramp_changed"); accept_event(); } } + //Hold alt key to duplicate selected color + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed && p_event.key.mod.alt ) { + + int x = p_event.mouse_button.x; + grabbed=_get_point_from_pos(x); + + if( grabbed != -1 ) { + int total_w = get_size().width-get_size().height-3; + ColorRamp::Point newPoint = points[grabbed]; + newPoint.offset=CLAMP(x/float(total_w),0,1); + + points.push_back(newPoint); + points.sort(); + for(int i=0;i<points.size();++i) { + if (points[i].offset==newPoint.offset) { + grabbed=i; + break; + } + } + + emit_signal("ramp_changed"); + update(); + } + } + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.button_index==1 && p_event.mouse_button.pressed) { update(); @@ -158,6 +185,33 @@ void ColorRampEdit::_input_event(const InputEvent& p_event) { int x = p_event.mouse_motion.x; float newofs = CLAMP(x/float(total_w),0,1); + + //Snap to nearest point if holding shift + if (p_event.key.mod.shift) { + float snap_treshhold = 0.03; + float smallest_ofs = snap_treshhold; + bool founded = false; + int nearest_point; + for(int i=0;i<points.size();++i) { + if (i != grabbed) { + float temp_ofs = ABS(points[i].offset - newofs); + if (temp_ofs < smallest_ofs) { + smallest_ofs = temp_ofs; + nearest_point = i; + if (founded) + break; + founded = true; + } + } + } + if (founded) { + if (points[nearest_point].offset < newofs) + newofs = points[nearest_point].offset+0.00001; + else + newofs = points[nearest_point].offset-0.00001; + newofs = CLAMP(newofs,0,1); + } + } bool valid=true; for(int i=0;i<points.size();i++) { diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 22559c238c..a1c0644650 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -136,27 +136,27 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) { if (p_value.get_type()==Variant::NIL) { if (name.begins_with("custom_icons/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); data.icon_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); update(); } else if (name.begins_with("custom_styles/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); data.style_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); update(); } else if (name.begins_with("custom_fonts/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); data.font_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); update(); } else if (name.begins_with("custom_colors/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); data.color_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); update(); } else if (name.begins_with("custom_constants/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); data.constant_override.erase(dname); notification(NOTIFICATION_THEME_CHANGED); update(); @@ -165,23 +165,23 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) { } else { if (name.begins_with("custom_icons/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); notification(NOTIFICATION_THEME_CHANGED); add_icon_override(dname,p_value); } else if (name.begins_with("custom_styles/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); add_style_override(dname,p_value); notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_fonts/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); add_font_override(dname,p_value); notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_colors/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); add_color_override(dname,p_value); notification(NOTIFICATION_THEME_CHANGED); } else if (name.begins_with("custom_constants/")) { - String dname = name.get_slice("/",1); + String dname = name.get_slicec('/',1); add_constant_override(dname,p_value); notification(NOTIFICATION_THEME_CHANGED); } else @@ -217,22 +217,22 @@ bool Control::_get(const StringName& p_name,Variant &r_ret) const { return false; if (sname.begins_with("custom_icons/")) { - String name = sname.get_slice("/",1); + String name = sname.get_slicec('/',1); r_ret= data.icon_override.has(name)?Variant(data.icon_override[name]):Variant(); } else if (sname.begins_with("custom_styles/")) { - String name = sname.get_slice("/",1); + String name = sname.get_slicec('/',1); r_ret= data.style_override.has(name)?Variant(data.style_override[name]):Variant(); } else if (sname.begins_with("custom_fonts/")) { - String name = sname.get_slice("/",1); + String name = sname.get_slicec('/',1); r_ret= data.font_override.has(name)?Variant(data.font_override[name]):Variant(); } else if (sname.begins_with("custom_colors/")) { - String name = sname.get_slice("/",1); + String name = sname.get_slicec('/',1); r_ret= data.color_override.has(name)?Variant(data.color_override[name]):Variant(); } else if (sname.begins_with("custom_constants/")) { - String name = sname.get_slice("/",1); + String name = sname.get_slicec('/',1); r_ret= data.constant_override.has(name)?Variant(data.constant_override[name]):Variant(); } else @@ -548,15 +548,18 @@ void Control::_notification(int p_notification) { Control * parent = get_parent()->cast_to<Control>(); //make children reference them theme - if (parent && data.theme.is_null() && parent->data.theme_owner) + + if (parent && data.theme.is_null() && parent->data.theme_owner) { _propagate_theme_changed(parent->data.theme_owner); + } } break; case NOTIFICATION_UNPARENTED: { //make children unreference the theme - if (data.theme.is_null() && data.theme_owner) + if (data.theme.is_null() && data.theme_owner) { _propagate_theme_changed(NULL); + } } break; case NOTIFICATION_MOVED_IN_PARENT: { @@ -2829,16 +2832,16 @@ void Control::_bind_methods() { ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/size", PROPERTY_HINT_NONE, "",PROPERTY_USAGE_EDITOR), _SCS("set_size"),_SCS("get_size") ); ADD_PROPERTYNZ( PropertyInfo(Variant::VECTOR2,"rect/min_size"), _SCS("set_custom_minimum_size"),_SCS("get_custom_minimum_size") ); ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"hint/tooltip", PROPERTY_HINT_MULTILINE_TEXT), _SCS("set_tooltip"),_SCS("_get_tooltip") ); - ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT ); - ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/top" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_TOP ); - ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/right" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_RIGHT ); - ADD_PROPERTYI( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/bottom" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_BOTTOM ); + ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/left" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_LEFT ); + ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/top" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_TOP ); + ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/right" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_RIGHT ); + ADD_PROPERTYINZ( PropertyInfo(Variant::NODE_PATH,"focus_neighbour/bottom" ), _SCS("set_focus_neighbour"),_SCS("get_focus_neighbour"),MARGIN_BOTTOM ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"focus/ignore_mouse"), _SCS("set_ignore_mouse"),_SCS("is_ignoring_mouse") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"focus/stop_mouse"), _SCS("set_stop_mouse"),_SCS("is_stopping_mouse") ); ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"size_flags/horizontal", PROPERTY_HINT_FLAGS, "Expand,Fill"), _SCS("set_h_size_flags"),_SCS("get_h_size_flags") ); ADD_PROPERTYNZ( PropertyInfo(Variant::INT,"size_flags/vertical", PROPERTY_HINT_FLAGS, "Expand,Fill"), _SCS("set_v_size_flags"),_SCS("get_v_size_flags") ); - ADD_PROPERTY( PropertyInfo(Variant::INT,"size_flags/stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), _SCS("set_stretch_ratio"),_SCS("get_stretch_ratio") ); + ADD_PROPERTYNO( PropertyInfo(Variant::INT,"size_flags/stretch_ratio", PROPERTY_HINT_RANGE, "1,128,0.01"), _SCS("set_stretch_ratio"),_SCS("get_stretch_ratio") ); ADD_PROPERTYNZ( PropertyInfo(Variant::OBJECT,"theme/theme", PROPERTY_HINT_RESOURCE_TYPE, "Theme"), _SCS("set_theme"),_SCS("get_theme") ); BIND_CONSTANT( ANCHOR_BEGIN ); diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 3ddf23fc4a..0c0f924f52 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -274,7 +274,7 @@ Button* AcceptDialog::add_button(const String& p_text,bool p_right,const String& } if (p_action!="") { - button->connect("pressed",this,"_custom_action",make_binds(p_action)); + button->connect("pressed",this,"_custom_action",varray(p_action)); } return button; diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index c53de6568a..8e428fd71c 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -686,7 +686,7 @@ void FileDialog::set_default_show_hidden_files(bool p_show) { FileDialog::FileDialog() { - show_hidden_files=true; + show_hidden_files=default_show_hidden_files; VBoxContainer *vbc = memnew( VBoxContainer ); add_child(vbc); diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index 2fd4d810de..40fade840c 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -11,6 +11,7 @@ void ItemList::add_item(const String& p_item,const Ref<Texture>& p_texture,bool item.selectable=p_selectable; item.selected=false; item.disabled=false; + item.custom_bg=Color(0,0,0,0); items.push_back(item); update(); @@ -26,6 +27,7 @@ void ItemList::add_icon_item(const Ref<Texture>& p_item,bool p_selectable){ item.selectable=p_selectable; item.selected=false; item.disabled=false; + item.custom_bg=Color(0,0,0,0); items.push_back(item); update(); @@ -85,6 +87,23 @@ Ref<Texture> ItemList::get_item_icon(int p_idx) const{ } +void ItemList::set_item_custom_bg_color(int p_idx,const Color& p_custom_bg_color) { + + ERR_FAIL_INDEX(p_idx,items.size()); + + items[p_idx].custom_bg=p_custom_bg_color; + +} + +Color ItemList::get_item_custom_bg_color(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,items.size(),Color()); + + return items[p_idx].custom_bg; + +} + + void ItemList::set_item_tag_icon(int p_idx,const Ref<Texture>& p_tag_icon){ @@ -168,6 +187,7 @@ void ItemList::select(int p_idx,bool p_single){ } current=p_idx; + ensure_selected_visible=false; } else { if (items[p_idx].selectable) { @@ -176,6 +196,7 @@ void ItemList::select(int p_idx,bool p_single){ } update(); + } void ItemList::unselect(int p_idx){ @@ -227,12 +248,14 @@ void ItemList::remove_item(int p_idx){ update(); shape_changed=true; + } void ItemList::clear(){ items.clear(); current=-1; + ensure_selected_visible=false; update(); } @@ -583,18 +606,8 @@ void ItemList::_input_event(const InputEvent& p_event) { void ItemList::ensure_current_is_visible() { - if (current>=0 && current <=items.size()) { - - Rect2 r = items[current].rect_cache; - int from = scroll_bar->get_val(); - int to = from + scroll_bar->get_page(); - - if (r.pos.y < from) { - scroll_bar->set_val(r.pos.y); - } else if (r.pos.y+r.size.y > to) { - scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); - } - } + ensure_selected_visible=true; + update(); } void ItemList::_notification(int p_what) { @@ -635,6 +648,7 @@ void ItemList::_notification(int p_what) { Ref<Font> font = get_font("font"); Color guide_color = get_color("guide_color"); Color font_color = get_color("font_color"); + Color font_color_selected = get_color("font_color_selected"); int font_height = font->get_height(); Vector<int> line_size_cache; Vector<int> line_limit_cache; @@ -781,6 +795,11 @@ void ItemList::_notification(int p_what) { if (current_columns==1) { rcache.size.width = width-rcache.pos.x; } + if (items[i].custom_bg.a>0.001) { + Rect2 r=rcache; + r.pos+=base_ofs; + draw_rect(r,items[i].custom_bg); + } if (items[i].selected) { Rect2 r=rcache; r.pos+=base_ofs; @@ -864,7 +883,7 @@ void ItemList::_notification(int p_what) { if (line>=max_text_lines) break; } - ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],font_color); + ofs+=font->draw_char(get_canvas_item(),text_ofs+Vector2(ofs+(max_len-line_size_cache[line])/2,line*(font_height+line_separation)).floor(),items[i].text[j],items[i].text[j+1],items[i].selected?font_color_selected:font_color); } //special multiline mode @@ -884,7 +903,7 @@ void ItemList::_notification(int p_what) { text_ofs+=base_ofs; text_ofs+=items[i].rect_cache.pos; - draw_string(font,text_ofs,items[i].text,font_color,max_len+1); + draw_string(font,text_ofs,items[i].text,items[i].selected?font_color_selected:font_color,max_len+1); } @@ -903,6 +922,24 @@ void ItemList::_notification(int p_what) { draw_line(Vector2(bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),Vector2(size.width-bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),guide_color); } + + if (ensure_selected_visible && current>=0 && current <=items.size()) { + + Rect2 r = items[current].rect_cache; + int from = scroll_bar->get_val(); + int to = from + scroll_bar->get_page(); + + if (r.pos.y < from) { + scroll_bar->set_val(r.pos.y); + } else if (r.pos.y+r.size.y > to) { + scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); + } + + + } + + ensure_selected_visible=false; + } } @@ -954,6 +991,30 @@ String ItemList::get_tooltip(const Point2& p_pos) const { } +void ItemList::sort_items_by_text() { + items.sort(); + update(); + if (select_mode==SELECT_SINGLE) { + for(int i=0;i<items.size();i++) { + if (items[i].selected) { + select(i); + return; + } + } + } +} + +int ItemList::find_metadata(const Variant& p_metadata) const { + + for(int i=0;i<items.size();i++) { + if (items[i].metadata==p_metadata) { + return i; + } + } + + return -1; + +} void ItemList::_bind_methods(){ @@ -964,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); @@ -972,6 +1033,12 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_item_disabled","idx","disabled"),&ItemList::set_item_disabled); ObjectTypeDB::bind_method(_MD("is_item_disabled","idx"),&ItemList::is_item_disabled); + ObjectTypeDB::bind_method(_MD("set_item_metadata","idx","metadata"),&ItemList::set_item_metadata); + ObjectTypeDB::bind_method(_MD("get_item_metadata","idx"),&ItemList::get_item_metadata); + + ObjectTypeDB::bind_method(_MD("set_item_custom_bg_color","idx","custom_bg_color"),&ItemList::set_item_custom_bg_color); + ObjectTypeDB::bind_method(_MD("get_item_custom_bg_color","idx"),&ItemList::get_item_custom_bg_color); + ObjectTypeDB::bind_method(_MD("set_item_tooltip","idx","tooltip"),&ItemList::set_item_tooltip); ObjectTypeDB::bind_method(_MD("get_item_tooltip","idx"),&ItemList::get_item_tooltip); @@ -983,6 +1050,7 @@ void ItemList::_bind_methods(){ ObjectTypeDB::bind_method(_MD("remove_item","idx"),&ItemList::remove_item); ObjectTypeDB::bind_method(_MD("clear"),&ItemList::clear); + ObjectTypeDB::bind_method(_MD("sort_items_by_text"),&ItemList::clear); ObjectTypeDB::bind_method(_MD("set_fixed_column_width","width"),&ItemList::set_fixed_column_width); ObjectTypeDB::bind_method(_MD("get_fixed_column_width"),&ItemList::get_fixed_column_width); @@ -1039,6 +1107,7 @@ ItemList::ItemList() { set_focus_mode(FOCUS_ALL); current_columns=1; search_time_msec=0; + ensure_selected_visible=false; } diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 6bbb416970..7cf58a6426 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -29,14 +29,20 @@ private: bool disabled; Variant metadata; String tooltip; + Color custom_bg; + Rect2 rect_cache; + + bool operator<(const Item& p_another) const { return text<p_another.text; } }; int current; bool shape_changed; + bool ensure_selected_visible; + Vector<Item> items; Vector<int> separators; @@ -85,6 +91,9 @@ public: void set_item_tooltip(int p_idx,const String& p_tooltip); String get_item_tooltip(int p_idx) const; + void set_item_custom_bg_color(int p_idx,const Color& p_custom_bg_color); + Color get_item_custom_bg_color(int p_idx) const; + void select(int p_idx,bool p_single=true); void unselect(int p_idx); bool is_selected(int p_idx) const; @@ -118,6 +127,8 @@ public: void ensure_current_is_visible(); + void sort_items_by_text(); + int find_metadata(const Variant& p_metadata) const; virtual String get_tooltip(const Point2& p_pos) const; diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index 27d0f568a2..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 ); @@ -613,22 +655,25 @@ void Label::_bind_methods() { BIND_CONSTANT( VALIGN_BOTTOM ); BIND_CONSTANT( VALIGN_FILL ); - ADD_PROPERTY( PropertyInfo( Variant::STRING, "text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL), _SCS("set_text"),_SCS("get_text") ); - ADD_PROPERTY( PropertyInfo( Variant::INT, "align", PROPERTY_HINT_ENUM,"Left,Center,Right,Fill" ),_SCS("set_align"),_SCS("get_align") ); - ADD_PROPERTY( PropertyInfo( Variant::INT, "valign", PROPERTY_HINT_ENUM,"Top,Center,Bottom,Fill" ),_SCS("set_valign"),_SCS("get_valign") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autowrap"),_SCS("set_autowrap"),_SCS("has_autowrap") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "uppercase"),_SCS("set_uppercase"),_SCS("is_uppercase") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::STRING, "text",PROPERTY_HINT_MULTILINE_TEXT,"",PROPERTY_USAGE_DEFAULT_INTL), _SCS("set_text"),_SCS("get_text") ); + 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/menu_button.cpp b/scene/gui/menu_button.cpp index 68fcb4bda8..13ff7074ea 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -124,7 +124,7 @@ void MenuButton::_set_items(const Array& p_items) { void MenuButton::_bind_methods() { - ObjectTypeDB::bind_method(_MD("get_popup"),&MenuButton::get_popup); + ObjectTypeDB::bind_method(_MD("get_popup:PopupMenu"),&MenuButton::get_popup); ObjectTypeDB::bind_method(_MD("_unhandled_key_input"),&MenuButton::_unhandled_key_input); ObjectTypeDB::bind_method(_MD("_set_items"),&MenuButton::_set_items); ObjectTypeDB::bind_method(_MD("_get_items"),&MenuButton::_get_items); diff --git a/scene/gui/patch_9_frame.cpp b/scene/gui/patch_9_frame.cpp new file mode 100644 index 0000000000..b6e261714c --- /dev/null +++ b/scene/gui/patch_9_frame.cpp @@ -0,0 +1,132 @@ +#include "patch_9_frame.h" + +#include "servers/visual_server.h" + +void Patch9Frame::_notification(int p_what) { + + if (p_what==NOTIFICATION_DRAW) { + + if (texture.is_null()) + return; + + + Size2 s=get_size(); + RID ci = get_canvas_item(); + VS::get_singleton()->canvas_item_add_style_box(ci,Rect2(Point2(),s),texture->get_rid(),Vector2(margin[MARGIN_LEFT],margin[MARGIN_TOP]),Vector2(margin[MARGIN_RIGHT],margin[MARGIN_BOTTOM]),draw_center,modulate); +// draw_texture_rect(texture,Rect2(Point2(),s),false,modulate); + +/* + Vector<Point2> points; + points.resize(4); + points[0]=Point2(0,0); + points[1]=Point2(s.x,0); + points[2]=Point2(s.x,s.y); + points[3]=Point2(0,s.y); + Vector<Point2> uvs; + uvs.resize(4); + uvs[0]=Point2(0,0); + uvs[1]=Point2(1,0); + uvs[2]=Point2(1,1); + uvs[3]=Point2(0,1); + + VisualServer::get_singleton()->canvas_item_add_primitive(ci,points,Vector<Color>(),uvs,texture->get_rid()); +*/ + } +} + +Size2 Patch9Frame::get_minimum_size() const { + + return Size2(margin[MARGIN_LEFT]+margin[MARGIN_RIGHT],margin[MARGIN_TOP]+margin[MARGIN_BOTTOM]); +} +void Patch9Frame::_bind_methods() { + + + ObjectTypeDB::bind_method(_MD("set_texture","texture"), & Patch9Frame::set_texture ); + ObjectTypeDB::bind_method(_MD("get_texture"), & Patch9Frame::get_texture ); + ObjectTypeDB::bind_method(_MD("set_modulate","modulate"), & Patch9Frame::set_modulate ); + ObjectTypeDB::bind_method(_MD("get_modulate"), & Patch9Frame::get_modulate ); + ObjectTypeDB::bind_method(_MD("set_patch_margin","margin","value"), & Patch9Frame::set_patch_margin ); + ObjectTypeDB::bind_method(_MD("get_patch_margin","margin"), & Patch9Frame::get_patch_margin ); + ObjectTypeDB::bind_method(_MD("set_draw_center","draw_center"), & Patch9Frame::set_draw_center ); + ObjectTypeDB::bind_method(_MD("get_draw_center"), & Patch9Frame::get_draw_center ); + + ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); + ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); + ADD_PROPERTYNO( PropertyInfo( Variant::BOOL, "draw_center"), _SCS("set_draw_center"),_SCS("get_draw_center") ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/left",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_LEFT ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/top",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_TOP ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/right",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_RIGHT ); + ADD_PROPERTYINZ( PropertyInfo( Variant::INT, "patch_margin/bottom",PROPERTY_HINT_RANGE,"0,16384,1"), _SCS("set_patch_margin"),_SCS("get_patch_margin"),MARGIN_BOTTOM ); + +} + + +void Patch9Frame::set_texture(const Ref<Texture>& p_tex) { + + texture=p_tex; + update(); + //if (texture.is_valid()) + // texture->set_flags(texture->get_flags()&(~Texture::FLAG_REPEAT)); //remove repeat from texture, it looks bad in sprites + minimum_size_changed(); +} + +Ref<Texture> Patch9Frame::get_texture() const { + + return texture; +} + +void Patch9Frame::set_modulate(const Color& p_tex) { + + modulate=p_tex; + update(); +} + +Color Patch9Frame::get_modulate() const{ + + return modulate; +} + + +void Patch9Frame::set_patch_margin(Margin p_margin,int p_size) { + + ERR_FAIL_INDEX(p_margin,4); + margin[p_margin]=p_size; + update(); + minimum_size_changed(); +} + +int Patch9Frame::get_patch_margin(Margin p_margin) const{ + + ERR_FAIL_INDEX_V(p_margin,4,0); + return margin[p_margin]; +} + +void Patch9Frame::set_draw_center(bool p_draw) { + + draw_center=p_draw; + update(); +} + +bool Patch9Frame::get_draw_center() const{ + + return draw_center; +} + +Patch9Frame::Patch9Frame() { + + + margin[MARGIN_LEFT]=0; + margin[MARGIN_RIGHT]=0; + margin[MARGIN_BOTTOM]=0; + margin[MARGIN_TOP]=0; + modulate=Color(1,1,1,1); + set_ignore_mouse(true); + draw_center=true; +} + + +Patch9Frame::~Patch9Frame() +{ +} + + diff --git a/scene/gui/patch_9_frame.h b/scene/gui/patch_9_frame.h new file mode 100644 index 0000000000..562a5b1d77 --- /dev/null +++ b/scene/gui/patch_9_frame.h @@ -0,0 +1,40 @@ +#ifndef PATCH_9_FRAME_H +#define PATCH_9_FRAME_H + +#include "scene/gui/control.h" +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ +class Patch9Frame : public Control { + + OBJ_TYPE(Patch9Frame,Control); + + bool draw_center; + int margin[4]; + Color modulate; + Ref<Texture> texture; +protected: + + void _notification(int p_what); + virtual Size2 get_minimum_size() const; + static void _bind_methods(); + +public: + + void set_texture(const Ref<Texture>& p_tex); + Ref<Texture> get_texture() const; + + void set_modulate(const Color& p_tex); + Color get_modulate() const; + + void set_patch_margin(Margin p_margin,int p_size); + int get_patch_margin(Margin p_margin) const; + + void set_draw_center(bool p_enable); + bool get_draw_center() const; + + Patch9Frame(); + ~Patch9Frame(); + +}; +#endif // PATCH_9_FRAME_H diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index c73af74426..5ce7e2e0d3 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -84,6 +84,48 @@ void Popup::_fix_size() { } +void Popup::set_as_minsize() { + + Size2 total_minsize; + + for(int i=0;i<get_child_count();i++) { + + Control *c=get_child(i)->cast_to<Control>(); + if (!c) + continue; + if (c->is_hidden()) + continue; + + Size2 minsize = c->get_combined_minimum_size(); + + for(int j=0;j<2;j++) { + + Margin m_beg = Margin(0+j); + Margin m_end = Margin(2+j); + + float margin_begin = c->get_margin(m_beg); + float margin_end = c->get_margin(m_end); + AnchorType anchor_begin = c->get_anchor(m_beg); + AnchorType anchor_end = c->get_anchor(m_end); + + if (anchor_begin == ANCHOR_BEGIN) + minsize[j]+=margin_begin; + if (anchor_end == ANCHOR_END) + minsize[j]+=margin_end; + + } + + print_line(String(c->get_type())+": "+minsize); + + total_minsize.width = MAX( total_minsize.width, minsize.width ); + total_minsize.height = MAX( total_minsize.height, minsize.height ); + } + + set_size(total_minsize); + +} + + void Popup::popup_centered_minsize(const Size2& p_minsize) { diff --git a/scene/gui/popup.h b/scene/gui/popup.h index c2de6c8cf7..6c72a3c82b 100644 --- a/scene/gui/popup.h +++ b/scene/gui/popup.h @@ -62,6 +62,7 @@ public: void popup_centered_ratio(float p_screen_ratio=0.75); void popup_centered(const Size2& p_size=Size2()); void popup_centered_minsize(const Size2& p_minsize=Size2()); + void set_as_minsize(); virtual void popup(); diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index e706053592..6c21ea639f 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -323,8 +323,10 @@ void PopupMenu::_input_event(const InputEvent &p_event) { invalidated_click=false; break; } - if (over<0 || items[over].separator || items[over].disabled) + if (over<0 || items[over].separator || items[over].disabled) { + hide(); break; //non-activable + } if (items[over].submenu!="") { @@ -738,10 +740,18 @@ int PopupMenu::find_item_by_accelerator(uint32_t p_accel) const { void PopupMenu::activate_item(int p_item) { - ERR_FAIL_INDEX(p_item,items.size()); ERR_FAIL_COND(items[p_item].separator); emit_signal("item_pressed",items[p_item].ID); + + //hide all parent PopupMenue's + Node *next = get_parent(); + PopupMenu *pop = next->cast_to<PopupMenu>(); + while (pop) { + pop->hide(); + next = next->get_parent(); + pop = next->cast_to<PopupMenu>(); + } hide(); } diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 41e775bbff..a48136f541 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -27,7 +27,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "spin_box.h" - +#include "os/input.h" Size2 SpinBox::get_minimum_size() const { @@ -62,6 +62,13 @@ LineEdit *SpinBox::get_line_edit() { } +void SpinBox::_line_edit_input(const InputEvent& p_event) { + + + +} + + void SpinBox::_input_event(const InputEvent& p_event) { if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed) { @@ -94,6 +101,48 @@ void SpinBox::_input_event(const InputEvent& p_event) { } break; } } + + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) { + + //set_default_cursor_shape(CURSOR_VSIZE); + Vector2 cpos = Vector2(p_event.mouse_button.x,p_event.mouse_button.y); + drag.mouse_pos=cpos; + } + + if (p_event.type==InputEvent::MOUSE_BUTTON && !p_event.mouse_button.pressed && p_event.mouse_button.button_index==1) { + + //set_default_cursor_shape(CURSOR_ARROW); + if (drag.enabled) { + drag.enabled=false; + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + warp_mouse(drag.capture_pos); + } + } + + if (p_event.type==InputEvent::MOUSE_MOTION && p_event.mouse_button.button_mask&1) { + + Vector2 cpos = Vector2(p_event.mouse_motion.x,p_event.mouse_motion.y); + if (drag.enabled) { + + float diff_y = drag.mouse_pos.y - cpos.y; + diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y); + diff_y*=0.1; + + drag.mouse_pos=cpos; + drag.base_val=CLAMP(drag.base_val + get_step() * diff_y, get_min(), get_max()); + + set_val( drag.base_val); + + } else if (drag.mouse_pos.distance_to(cpos)>2) { + + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + drag.enabled=true; + drag.base_val=get_val(); + drag.mouse_pos=cpos; + drag.capture_pos=cpos; + + } + } } @@ -177,6 +226,7 @@ void SpinBox::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_editable"),&SpinBox::is_editable); ObjectTypeDB::bind_method(_MD("_line_edit_focus_exit"),&SpinBox::_line_edit_focus_exit); ObjectTypeDB::bind_method(_MD("get_line_edit"),&SpinBox::get_line_edit); + ObjectTypeDB::bind_method(_MD("_line_edit_input"),&SpinBox::_line_edit_input); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"editable"),_SCS("set_editable"),_SCS("is_editable")); @@ -196,4 +246,6 @@ SpinBox::SpinBox() { //connect("value_changed",this,"_value_changed"); line_edit->connect("text_entered",this,"_text_entered",Vector<Variant>(),CONNECT_DEFERRED); line_edit->connect("focus_exit",this,"_line_edit_focus_exit",Vector<Variant>(),CONNECT_DEFERRED); + line_edit->connect("input_event",this,"_line_edit_input"); + drag.enabled=false; } diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h index 6ebe14631e..4c8cb8432a 100644 --- a/scene/gui/spin_box.h +++ b/scene/gui/spin_box.h @@ -44,6 +44,18 @@ class SpinBox : public Range { String prefix; String suffix; + void _line_edit_input(const InputEvent& p_event); + + + struct Drag { + float base_val; + bool enabled; + Vector2 from; + Vector2 mouse_pos; + Vector2 capture_pos; + } drag; + + void _line_edit_focus_exit(); protected: diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp index d02c833be9..d7ee7a6b86 100644 --- a/scene/gui/split_container.cpp +++ b/scene/gui/split_container.cpp @@ -345,6 +345,7 @@ void SplitContainer::_input_event(const InputEvent& p_event) { expand_ofs=drag_ofs+((vertical?mm.y:mm.x)-drag_from); queue_sort(); + emit_signal("dragged",get_split_offset()); } } @@ -431,11 +432,13 @@ void SplitContainer::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_dragger_visible","visible"),&SplitContainer::set_dragger_visible); ObjectTypeDB::bind_method(_MD("is_dragger_visible"),&SplitContainer::is_dragger_visible); + ADD_SIGNAL( MethodInfo("dragged",PropertyInfo(Variant::INT,"offset"))); ADD_PROPERTY( PropertyInfo(Variant::INT,"split/offset"),_SCS("set_split_offset"),_SCS("get_split_offset")); ADD_PROPERTY( PropertyInfo(Variant::INT,"split/collapsed"),_SCS("set_collapsed"),_SCS("is_collapsed")); ADD_PROPERTY( PropertyInfo(Variant::INT,"split/dragger_visible"),_SCS("set_dragger_visible"),_SCS("is_dragger_visible")); + } SplitContainer::SplitContainer(bool p_vertical) { diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 1db4998a27..3ed182c017 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -88,7 +88,22 @@ void TabContainer::_input_event(const InputEvent& p_event) { Ref<Font> font = get_font("font"); Ref<Texture> incr = get_icon("increment"); Ref<Texture> decr = get_icon("decrement"); + Ref<Texture> menu = get_icon("menu"); + Ref<Texture> menu_hl = get_icon("menu_hl"); + if (popup && pos.x>get_size().width-menu->get_width()) { + + + emit_signal("pre_popup_pressed"); + Vector2 pp_pos = get_global_pos(); + pp_pos.x+=get_size().width; + pp_pos.x-=popup->get_size().width; + pp_pos.y+=menu->get_height(); + + popup->set_global_pos( pp_pos ); + popup->popup();; + return; + } pos.x-=tabs_ofs_cache; int idx=0; @@ -116,17 +131,17 @@ void TabContainer::_input_event(const InputEvent& p_event) { String s = c->has_meta("_tab_name")?String(XL_MESSAGE(String(c->get_meta("_tab_name")))):String(c->get_name()); int tab_width=font->get_string_size(s).width; - if (c->has_meta("_tab_icon")) { - Ref<Texture> icon = c->get_meta("_tab_icon"); - if (icon.is_valid()) { - tab_width+=icon->get_width(); - if (s!="") - tab_width+=get_constant("hseparation"); + if (c->has_meta("_tab_icon")) { + Ref<Texture> icon = c->get_meta("_tab_icon"); + if (icon.is_valid()) { + tab_width+=icon->get_width(); + if (s!="") + tab_width+=get_constant("hseparation"); - } - } + } + } - if (idx==current) { + if (idx==current) { tab_width+=tab_fg->get_minimum_size().width; } else { @@ -163,7 +178,7 @@ void TabContainer::_input_event(const InputEvent& p_event) { if (found!=-1) { - set_current_tab(found); + set_current_tab(found); } } @@ -194,7 +209,9 @@ void TabContainer::_notification(int p_what) { Ref<Texture> incr = get_icon("increment"); Ref<Texture> incr_hl = get_icon("increment_hilite"); Ref<Texture> decr = get_icon("decrement"); - Ref<Texture> decr_hl = get_icon("decrement_hilite"); + Ref<Texture> decr_hl = get_icon("decrement_hilite"); + Ref<Texture> menu = get_icon("menu"); + Ref<Texture> menu_hl = get_icon("menu_hl"); Ref<Font> font = get_font("font"); Color color_fg = get_color("font_color_fg"); Color color_bg = get_color("font_color_bg"); @@ -209,6 +226,7 @@ void TabContainer::_notification(int p_what) { Size2 top_size = Size2( size.width, top_margin ); + int w=0; int idx=0; for(int i=0;i<get_child_count();i++) { @@ -227,7 +245,7 @@ void TabContainer::_notification(int p_what) { if (icon.is_valid()) { w+=icon->get_width(); if (s!="") - w+=get_constant("hseparation"); + w+=get_constant("hseparation"); } } @@ -245,14 +263,18 @@ void TabContainer::_notification(int p_what) { int ofs; int limit=get_size().width; + if (popup) { + top_size.width-=menu->get_width(); + limit-=menu->get_width(); + } - if (w<=get_size().width) { + if (w<=limit) { switch(align) { case ALIGN_LEFT: ofs = side_margin; break; - case ALIGN_CENTER: ofs = (int(top_size.width) - w)/2; break; - case ALIGN_RIGHT: ofs = int(top_size.width) - w - side_margin; break; + case ALIGN_CENTER: ofs = (int(limit) - w)/2; break; + case ALIGN_RIGHT: ofs = int(limit) - w - side_margin; break; }; tab_display_ofs=0; @@ -364,6 +386,15 @@ void TabContainer::_notification(int p_what) { incr->draw(ci,Point2(limit+incr->get_width(),vofs),Color(1,1,1,notdone?1.0:0.5)); } + if (popup) { + int from = get_size().width-menu->get_width(); + + if (mouse_x_cache > from) + menu_hl->draw(get_canvas_item(),Size2(from,0)); + else + menu->draw(get_canvas_item(),Size2(from,0)); + } + panel->draw(ci, Rect2( 0, top_size.height, size.width, size.height-top_size.height)); } break; @@ -465,6 +496,48 @@ int TabContainer::get_current_tab() const { return current; } +Control* TabContainer::get_tab_control(int p_idx) const { + + int idx=0; + + + for(int i=0;i<get_child_count();i++) { + + Control *c = get_child(i)->cast_to<Control>(); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + if (idx==p_idx) { + return c; + + } + idx++; + } + + return NULL; +} +Control* TabContainer::get_current_tab_control() const { + + int idx=0; + + + for(int i=0;i<get_child_count();i++) { + + Control *c = get_child(i)->cast_to<Control>(); + if (!c) + continue; + if (c->is_set_as_toplevel()) + continue; + if (idx==current) { + return c; + + } + idx++; + } + + return NULL; +} void TabContainer::remove_child_notify(Node *p_child) { @@ -635,12 +708,25 @@ Size2 TabContainer::get_minimum_size() const { return ms; } +void TabContainer::set_popup(Node *p_popup) { + ERR_FAIL_NULL(p_popup); + popup=p_popup->cast_to<Popup>(); + update(); +} + +Popup* TabContainer::get_popup() const { + return popup; +} + + void TabContainer::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&TabContainer::_input_event); ObjectTypeDB::bind_method(_MD("get_tab_count"),&TabContainer::get_tab_count); ObjectTypeDB::bind_method(_MD("set_current_tab","tab_idx"),&TabContainer::set_current_tab); ObjectTypeDB::bind_method(_MD("get_current_tab"),&TabContainer::get_current_tab); + ObjectTypeDB::bind_method(_MD("get_current_tab_control:Control"),&TabContainer::get_current_tab_control); + ObjectTypeDB::bind_method(_MD("get_tab_control:Control","idx"),&TabContainer::get_tab_control); ObjectTypeDB::bind_method(_MD("set_tab_align","align"),&TabContainer::set_tab_align); ObjectTypeDB::bind_method(_MD("get_tab_align"),&TabContainer::get_tab_align); ObjectTypeDB::bind_method(_MD("set_tabs_visible","visible"),&TabContainer::set_tabs_visible); @@ -649,10 +735,13 @@ void TabContainer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tab_title","tab_idx"),&TabContainer::get_tab_title); ObjectTypeDB::bind_method(_MD("set_tab_icon","tab_idx","icon:Texture"),&TabContainer::set_tab_icon); ObjectTypeDB::bind_method(_MD("get_tab_icon:Texture","tab_idx"),&TabContainer::get_tab_icon); + ObjectTypeDB::bind_method(_MD("set_popup","popup:Popup"),&TabContainer::set_popup); + ObjectTypeDB::bind_method(_MD("get_popup:Popup"),&TabContainer::get_popup); ObjectTypeDB::bind_method(_MD("_child_renamed_callback"),&TabContainer::_child_renamed_callback); ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab"))); + ADD_SIGNAL(MethodInfo("pre_popup_pressed")); ADD_PROPERTY( PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM,"Left,Center,Right"), _SCS("set_tab_align"), _SCS("get_tab_align") ); ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") ); @@ -669,5 +758,6 @@ TabContainer::TabContainer() { mouse_x_cache=0; align=ALIGN_CENTER; tabs_visible=true; + popup=NULL; } diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index 43314b026d..602d248b46 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -31,7 +31,7 @@ #include "scene/gui/control.h" - +#include "scene/gui/popup.h" class TabContainer : public Control { OBJ_TYPE( TabContainer, Control ); @@ -55,6 +55,8 @@ private: TabAlign align; Control *_get_tab(int idx) const; int _get_top_margin() const; + Popup *popup; + protected: @@ -85,10 +87,17 @@ public: void set_current_tab(int p_current); int get_current_tab() const; + Control* get_tab_control(int p_idx) const; + Control* get_current_tab_control() const; + virtual Size2 get_minimum_size() const; virtual void get_translatable_strings(List<String> *p_strings) const; + void set_popup(Node *p_popup); + Popup* get_popup() const; + + TabContainer(); }; diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp index 37369a7e6c..6d84f028b3 100644 --- a/scene/gui/tabs.cpp +++ b/scene/gui/tabs.cpp @@ -56,7 +56,23 @@ Size2 Tabs::get_minimum_size() const { else ms.width+=tab_bg->get_minimum_size().width; + if (tabs[i].right_button.is_valid()) { + Ref<Texture> rb=tabs[i].right_button; + Size2 bms = rb->get_size()+get_stylebox("button")->get_minimum_size(); + bms.width+=get_constant("hseparation"); + ms.width+=bms.width; + ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); + } + + if (tabs[i].close_button.is_valid()) { + Ref<Texture> cb=tabs[i].close_button; + Size2 bms = cb->get_size()+get_stylebox("button")->get_minimum_size(); + bms.width+=get_constant("hseparation"); + + ms.width+=bms.width; + ms.height=MAX(bms.height+tab_bg->get_minimum_size().height,ms.height); + } } return ms; @@ -66,6 +82,79 @@ Size2 Tabs::get_minimum_size() const { void Tabs::_input_event(const InputEvent& p_event) { + if (p_event.type==InputEvent::MOUSE_MOTION) { + + Point2 pos( p_event.mouse_motion.x, p_event.mouse_motion.y ); + + int hover_buttons=-1; + hover=-1; + for(int i=0;i<tabs.size();i++) { + + // test hovering tab to display close button if policy says so + if (cb_displaypolicy == SHOW_HOVER) { + int ofs=tabs[i].ofs_cache; + int size = tabs[i].ofs_cache; + if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) { + hover=i; + } + } + + + // test hovering right button and close button + if (tabs[i].rb_rect.has_point(pos)) { + rb_hover=i; + hover_buttons = i; + break; + } + else if (tabs[i].cb_rect.has_point(pos)) { + cb_hover=i; + hover_buttons = i; + break; + } + + + + } + + if (hover_buttons == -1) { // no hover + rb_hover= hover_buttons; + cb_hover= hover_buttons; + } + update(); + + return; + } + + + + + if (rb_pressing && p_event.type==InputEvent::MOUSE_BUTTON && + !p_event.mouse_button.pressed && + p_event.mouse_button.button_index==BUTTON_LEFT) { + + if (rb_hover!=-1) { + //pressed + emit_signal("right_button_pressed",rb_hover); + } + + rb_pressing=false; + update(); + } + + if (cb_pressing && p_event.type==InputEvent::MOUSE_BUTTON && + !p_event.mouse_button.pressed && + p_event.mouse_button.button_index==BUTTON_LEFT) { + + if (cb_hover!=-1) { + //pressed + emit_signal("tab_close",cb_hover); + } + + cb_pressing=false; + update(); + } + + if (p_event.type==InputEvent::MOUSE_BUTTON && p_event.mouse_button.pressed && p_event.mouse_button.button_index==BUTTON_LEFT) { @@ -76,9 +165,21 @@ void Tabs::_input_event(const InputEvent& p_event) { int found=-1; for(int i=0;i<tabs.size();i++) { - int ofs=tabs[i].ofs_cache; + if (tabs[i].rb_rect.has_point(pos)) { + rb_pressing=true; + update(); + return; + } + + if (tabs[i].cb_rect.has_point(pos)) { + cb_pressing=true; + update(); + return; + } - if (pos.x < ofs) { + int ofs=tabs[i].ofs_cache; + int size = tabs[i].ofs_cache; + if (pos.x >=tabs[i].ofs_cache && pos.x<tabs[i].ofs_cache+tabs[i].size_cache) { found=i; break; @@ -89,6 +190,7 @@ void Tabs::_input_event(const InputEvent& p_event) { if (found!=-1) { set_current_tab(found); + emit_signal("tab_changed",found); } } @@ -99,7 +201,12 @@ void Tabs::_notification(int p_what) { switch(p_what) { - + case NOTIFICATION_MOUSE_EXIT: { + rb_hover=-1; + cb_hover=-1; + hover=-1; + update(); + } break; case NOTIFICATION_DRAW: { RID ci = get_canvas_item(); @@ -117,17 +224,31 @@ void Tabs::_notification(int p_what) { int w=0; + int mw = get_minimum_size().width; + + if (tab_align==ALIGN_CENTER) { + w=(get_size().width-mw)/2; + } else if (tab_align==ALIGN_RIGHT) { + w=get_size().width-mw; + + } + + if (w<0) { + w=0; + } + for(int i=0;i<tabs.size();i++) { + tabs[i].ofs_cache=w; String s = tabs[i].text; int lsize=0; - int slen=font->get_string_size(s).width;; + int slen=font->get_string_size(s).width; lsize+=slen; Ref<Texture> icon; if (tabs[i].icon.is_valid()) { - Ref<Texture> icon = tabs[i].icon; + icon = tabs[i].icon; if (icon.is_valid()) { lsize+=icon->get_width(); if (s!="") @@ -136,6 +257,66 @@ void Tabs::_notification(int p_what) { } } + if (tabs[i].right_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].right_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + + // Close button + switch (cb_displaypolicy) { + case SHOW_ALWAYS: { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].close_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + } break; + case SHOW_ACTIVE_ONLY: { + if (i==current) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].close_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + } + } break; + case SHOW_HOVER: { + if (i==current || i==hover) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].close_button; + + lsize+=get_constant("hseparation"); + lsize+=style->get_margin(MARGIN_LEFT); + lsize+=rb->get_width(); + lsize+=style->get_margin(MARGIN_RIGHT); + + } + } + } break; + case SHOW_NEVER: // by default, never show close button + default: { + // do nothing + } break; + + } + Ref<StyleBox> sb; int va; @@ -169,9 +350,136 @@ void Tabs::_notification(int p_what) { font->draw(ci, Point2i( w, sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-font->get_height())/2+font->get_ascent() ), s, col ); - w+=slen+sb->get_margin(MARGIN_RIGHT); + w+=slen; - tabs[i].ofs_cache=w; + if (tabs[i].right_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> rb=tabs[i].right_button; + + w+=get_constant("hseparation"); + + Rect2 rb_rect; + rb_rect.size=style->get_minimum_size()+rb->get_size(); + rb_rect.pos.x=w; + rb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(rb_rect.size.y))/2; + + if (rb_hover==i) { + if (rb_pressing) + get_stylebox("button_pressed")->draw(ci,rb_rect); + else + style->draw(ci,rb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + rb->draw(ci,Point2i( w,rb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=rb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].rb_rect=rb_rect; + + + } + + + + + // Close button + switch (cb_displaypolicy) { + case SHOW_ALWAYS: { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> cb=tabs[i].close_button; + + w+=get_constant("hseparation"); + + Rect2 cb_rect; + cb_rect.size=style->get_minimum_size()+cb->get_size(); + cb_rect.pos.x=w; + cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2; + + if (cb_hover==i) { + if (cb_pressing) + get_stylebox("button_pressed")->draw(ci,cb_rect); + else + style->draw(ci,cb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=cb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].cb_rect=cb_rect; + } + } break; + case SHOW_ACTIVE_ONLY: { + if (current==i) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> cb=tabs[i].close_button; + + w+=get_constant("hseparation"); + + Rect2 cb_rect; + cb_rect.size=style->get_minimum_size()+cb->get_size(); + cb_rect.pos.x=w; + cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2; + + if (cb_hover==i) { + if (cb_pressing) + get_stylebox("button_pressed")->draw(ci,cb_rect); + else + style->draw(ci,cb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=cb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].cb_rect=cb_rect; + } + } + } break; + case SHOW_HOVER: { + if (current==i || hover==i) { + if (tabs[i].close_button.is_valid()) { + Ref<StyleBox> style = get_stylebox("button"); + Ref<Texture> cb=tabs[i].close_button; + + w+=get_constant("hseparation"); + + Rect2 cb_rect; + cb_rect.size=style->get_minimum_size()+cb->get_size(); + cb_rect.pos.x=w; + cb_rect.pos.y=sb->get_margin(MARGIN_TOP)+((sb_rect.size.y-sb_ms.y)-(cb_rect.size.y))/2; + + if (cb_hover==i) { + if (cb_pressing) + get_stylebox("button_pressed")->draw(ci,cb_rect); + else + style->draw(ci,cb_rect); + } + + w+=style->get_margin(MARGIN_LEFT); + + cb->draw(ci,Point2i( w,cb_rect.pos.y+style->get_margin(MARGIN_TOP) )); + w+=cb->get_width(); + w+=style->get_margin(MARGIN_RIGHT); + tabs[i].cb_rect=cb_rect; + } + } + } break; + case SHOW_NEVER: + default: { + // show nothing + } break; + + } + + w+=sb->get_margin(MARGIN_RIGHT); + + tabs[i].size_cache=w-tabs[i].ofs_cache; } @@ -195,7 +503,7 @@ void Tabs::set_current_tab(int p_current) { current=p_current; _change_notify("current_tab"); - emit_signal("tab_changed",current); + //emit_signal("tab_changed",current); update(); } @@ -237,11 +545,46 @@ Ref<Texture> Tabs::get_tab_icon(int p_tab) const{ } + + +void Tabs::set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button){ + + ERR_FAIL_INDEX(p_tab,tabs.size()); + tabs[p_tab].right_button=p_right_button; + update(); + minimum_size_changed(); + +} +Ref<Texture> Tabs::get_tab_right_button(int p_tab) const{ + + ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>()); + return tabs[p_tab].right_button; + +} + +void Tabs::set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button) { + ERR_FAIL_INDEX(p_tab, tabs.size()); + tabs[p_tab].close_button=p_close_button; + update(); + minimum_size_changed(); +} + + +Ref<Texture> Tabs::get_tab_close_button(int p_tab) const{ + + ERR_FAIL_INDEX_V(p_tab,tabs.size(),Ref<Texture>()); + return tabs[p_tab].close_button; + +} + void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) { Tab t; t.text=p_str; t.icon=p_icon; + + t.close_button = get_icon("Close","EditorIcons"); + tabs.push_back(t); update(); @@ -249,6 +592,12 @@ void Tabs::add_tab(const String& p_str,const Ref<Texture>& p_icon) { } +void Tabs::clear_tabs() { + tabs.clear(); + current=0; + update(); +} + void Tabs::remove_tab(int p_idx) { ERR_FAIL_INDEX(p_idx,tabs.size()); @@ -263,10 +612,26 @@ void Tabs::remove_tab(int p_idx) { if (current>=tabs.size()) current=tabs.size()-1; - emit_signal("tab_changed",current); + //emit_signal("tab_changed",current); } +void Tabs::set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy) { + cb_displaypolicy = p_cb_displaypolicy; +} + + +void Tabs::set_tab_align(TabAlign p_align) { + + tab_align=p_align; + update(); +} + +Tabs::TabAlign Tabs::get_tab_align() const { + + return tab_align; +} + void Tabs::_bind_methods() { @@ -280,15 +645,35 @@ void Tabs::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tab_icon:Texture","tab_idx"),&Tabs::get_tab_icon); ObjectTypeDB::bind_method(_MD("remove_tab","tab_idx"),&Tabs::remove_tab); ObjectTypeDB::bind_method(_MD("add_tab","title","icon:Texture"),&Tabs::add_tab); + ObjectTypeDB::bind_method(_MD("set_tab_align","align"),&Tabs::set_tab_align); + ObjectTypeDB::bind_method(_MD("get_tab_align"),&Tabs::get_tab_align); ADD_SIGNAL(MethodInfo("tab_changed",PropertyInfo(Variant::INT,"tab"))); + ADD_SIGNAL(MethodInfo("right_button_pressed",PropertyInfo(Variant::INT,"tab"))); + ADD_SIGNAL(MethodInfo("tab_close",PropertyInfo(Variant::INT,"tab"))); + ADD_PROPERTY( PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE,"-1,4096,1",PROPERTY_USAGE_EDITOR), _SCS("set_current_tab"), _SCS("get_current_tab") ); + BIND_CONSTANT( ALIGN_LEFT ); + BIND_CONSTANT( ALIGN_CENTER ); + BIND_CONSTANT( ALIGN_RIGHT ); + + BIND_CONSTANT( SHOW_ACTIVE_ONLY ); + BIND_CONSTANT( SHOW_ALWAYS ); + BIND_CONSTANT( SHOW_HOVER ); + BIND_CONSTANT( SHOW_NEVER ); } + Tabs::Tabs() { current=0; + tab_align=ALIGN_CENTER; + rb_hover=-1; + rb_pressing=false; + cb_hover=-1; + cb_pressing=false; + cb_displaypolicy = SHOW_NEVER; // Default : no close button } diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h index 4a969928ff..1a8352bc93 100644 --- a/scene/gui/tabs.h +++ b/scene/gui/tabs.h @@ -34,6 +34,22 @@ class Tabs : public Control { OBJ_TYPE( Tabs, Control ); +public: + + enum TabAlign { + + ALIGN_LEFT, + ALIGN_CENTER, + ALIGN_RIGHT + }; + + enum CloseButtonDisplayPolicy { + + SHOW_ALWAYS, + SHOW_ACTIVE_ONLY, + SHOW_HOVER, + SHOW_NEVER + }; private: @@ -42,12 +58,26 @@ private: String text; Ref<Texture> icon; int ofs_cache; + int size_cache; + Ref<Texture> right_button; + Rect2 rb_rect; + Ref<Texture> close_button; + Rect2 cb_rect; }; Vector<Tab> tabs; int current; Control *_get_tab(int idx) const; int _get_top_margin() const; + TabAlign tab_align; + int rb_hover; + bool rb_pressing; + + int cb_hover; + bool cb_pressing; + CloseButtonDisplayPolicy cb_displaypolicy; + + int hover; // hovered tab protected: @@ -65,16 +95,29 @@ public: void set_tab_icon(int p_tab,const Ref<Texture>& p_icon); Ref<Texture> get_tab_icon(int p_tab) const; + void set_tab_right_button(int p_tab,const Ref<Texture>& p_right_button); + Ref<Texture> get_tab_right_button(int p_tab) const; + + void set_tab_close_button(int p_tab, const Ref<Texture>& p_close_button); + Ref<Texture> get_tab_close_button(int p_tab) const; + void set_tab_close_display_policy(CloseButtonDisplayPolicy p_cb_displaypolicy); + + void set_tab_align(TabAlign p_align); + TabAlign get_tab_align() const; + int get_tab_count() const; void set_current_tab(int p_current); int get_current_tab() const; void remove_tab(int p_idx); + void clear_tabs(); + Size2 get_minimum_size() const; Tabs(); }; +VARIANT_ENUM_CAST(Tabs::TabAlign); #endif // TABS_H diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c497bc5363..048901a879 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(); @@ -706,7 +709,7 @@ void TextEdit::_notification(int p_what) { if (in_region==-1 && !in_keyword && is_char && !prev_is_char) { int to=j; - while(_is_text_char(str[to]) && to<str.length()) + while(to<str.length() && _is_text_char(str[to])) to++; uint32_t hash = String::hash(&str[j],to-j); @@ -1842,6 +1845,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.mod.shift) _post_shift_selection(); + _cancel_completion(); + completion_hint=""; } break; case KEY_END: { @@ -1855,6 +1860,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.mod.shift) _post_shift_selection(); + + _cancel_completion(); + completion_hint=""; } break; #endif @@ -1867,6 +1875,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.mod.shift) _post_shift_selection(); + + _cancel_completion(); + completion_hint=""; + } break; case KEY_PAGEDOWN: { @@ -1878,6 +1890,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.mod.shift) _post_shift_selection(); + + _cancel_completion(); + completion_hint=""; + } break; case KEY_A: { @@ -2064,6 +2080,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { const CharType chr[2] = {(CharType)k.unicode, 0}; + if (completion_hint!="" && k.unicode==')') { + completion_hint=""; + } if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { _consume_pair_symbol(chr[0]); } else { @@ -3323,9 +3342,32 @@ void TextEdit::_update_completion_candidates() { //look for keywords first - bool pre_keyword=false; + bool inquote=false; + int first_quote=-1; + + int c=cofs-1; + while(c>=0) { + if (l[c]=='"' || l[c]=='\'') { + inquote=!inquote; + if (first_quote==-1) + first_quote=c; + } + c--; + } - if (cofs>0 && l[cofs-1]==' ') { + bool pre_keyword=false; + bool cancel=false; + + //print_line("inquote: "+itos(inquote)+"first quote "+itos(first_quote)+" cofs-1 "+itos(cofs-1)); + if (!inquote && first_quote==cofs-1) { + //no completion here + //print_line("cancel!"); + cancel=true; + } if (inquote && first_quote!=-1) { + + s=l.substr(first_quote,cofs-first_quote); + //print_line("s: 1"+s); + } else if (cofs>0 && l[cofs-1]==' ') { int kofs=cofs-1; String kw; while (kofs>=0 && l[kofs]==' ') @@ -3337,7 +3379,7 @@ void TextEdit::_update_completion_candidates() { } pre_keyword=keywords.has(kw); - print_line("KW "+kw+"? "+itos(pre_keyword)); + //print_line("KW "+kw+"? "+itos(pre_keyword)); } else { @@ -3354,7 +3396,7 @@ void TextEdit::_update_completion_candidates() { update(); - if (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { + if (cancel || (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1]))))) { //none to complete, cancel _cancel_completion(); return; @@ -3421,7 +3463,16 @@ void TextEdit::query_code_comple() { String l = text[cursor.line]; int ofs = CLAMP(cursor.column,0,l.length()); - if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1])))) + bool inquote=false; + + int c=ofs-1; + while(c>=0) { + if (l[c]=='"' || l[c]=='\'') + inquote=!inquote; + c--; + } + + if (ofs>0 && (inquote || _is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1])))) emit_signal("request_completion"); } diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 823fd55c6e..5b2caecb5b 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -157,14 +157,14 @@ void TextureButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_scale"),&TextureButton::get_scale); ObjectTypeDB::bind_method(_MD("get_modulate"),&TextureButton::get_modulate); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_normal_texture"), _SCS("get_normal_texture")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_pressed_texture"), _SCS("get_pressed_texture")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/hover",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_hover_texture"), _SCS("get_hover_texture")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/disabled",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_disabled_texture"), _SCS("get_disabled_texture")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/focused",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_focused_texture"), _SCS("get_focused_texture")); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT,"textures/click_mask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"), _SCS("set_click_mask"), _SCS("get_click_mask")) ; - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2,"params/scale",PROPERTY_HINT_RANGE,"0.01,1024,0.01"), _SCS("set_scale"), _SCS("get_scale")); - ADD_PROPERTY(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/normal",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_normal_texture"), _SCS("get_normal_texture")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/pressed",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_pressed_texture"), _SCS("get_pressed_texture")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/hover",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_hover_texture"), _SCS("get_hover_texture")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/disabled",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_disabled_texture"), _SCS("get_disabled_texture")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/focused",PROPERTY_HINT_RESOURCE_TYPE,"Texture"), _SCS("set_focused_texture"), _SCS("get_focused_texture")); + ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT,"textures/click_mask",PROPERTY_HINT_RESOURCE_TYPE,"BitMap"), _SCS("set_click_mask"), _SCS("get_click_mask")) ; + ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2,"params/scale",PROPERTY_HINT_RANGE,"0.01,1024,0.01"), _SCS("set_scale"), _SCS("get_scale")); + ADD_PROPERTYNO(PropertyInfo(Variant::COLOR,"params/modulate"), _SCS("set_modulate"), _SCS("get_modulate")); } diff --git a/scene/gui/texture_frame.cpp b/scene/gui/texture_frame.cpp index 931fb1cb1a..5a6bc86638 100644 --- a/scene/gui/texture_frame.cpp +++ b/scene/gui/texture_frame.cpp @@ -77,9 +77,9 @@ void TextureFrame::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_expand","enable"), & TextureFrame::set_expand ); ObjectTypeDB::bind_method(_MD("has_expand"), & TextureFrame::has_expand ); - ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); - ADD_PROPERTY( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), _SCS("set_texture"),_SCS("get_texture") ); + ADD_PROPERTYNO( PropertyInfo( Variant::COLOR, "modulate"), _SCS("set_modulate"),_SCS("get_modulate") ); + ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "expand" ), _SCS("set_expand"),_SCS("has_expand") ); } diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index a09920cb2b..e639b5cb05 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -31,7 +31,7 @@ #include "os/os.h" #include "os/keyboard.h" #include "globals.h" - +#include "os/input.h" @@ -70,6 +70,7 @@ Size2 TreeItem::Cell::get_icon_size() const { else return icon_region.size; } + void TreeItem::Cell::draw_icon(const RID& p_where, const Point2& p_pos, const Size2& p_size) const{ if (icon.is_null()) @@ -728,14 +729,20 @@ TreeItem::~TreeItem() { tree->root=0; } - if (tree && tree->popup_edited_item==this) + if (tree && tree->popup_edited_item==this) { tree->popup_edited_item=NULL; + tree->pressing_for_editor=false; + + } if (tree && tree->selected_item==this) tree->selected_item=NULL; - if (tree && tree->edited_item==this) + if (tree && tree->edited_item==this) { tree->edited_item=NULL; + tree->pressing_for_editor=false; + } + } @@ -1106,7 +1113,7 @@ int Tree::draw_item(const Point2i& p_pos,const Point2& p_draw_ofs, const Size2& int option = (int)p_item->cells[i].val; String s = p_item->cells[i].text; - s=s.get_slice(",",option); + s=s.get_slicec(',',option); Ref<Texture> downarrow = cache.select_arrow; @@ -1292,7 +1299,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col } else if (select_mode==SELECT_SINGLE || select_mode==SELECT_MULTI) { - if (&selected_cell==&c) { + if (!r_in_range && &selected_cell==&c) { if (!selected_cell.selected) { @@ -1301,6 +1308,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col selected_item=p_selected; selected_col=i; + emit_signal("cell_selected"); if (select_mode==SELECT_MULTI) emit_signal("multi_selected",p_current,i,true); @@ -1317,6 +1325,7 @@ void Tree::select_single_item(TreeItem *p_selected,TreeItem *p_current,int p_col if (r_in_range && *r_in_range) { + if (!c.selected && c.selectable) { c.selected=true; emit_signal("multi_selected",p_current,i,true); @@ -1467,7 +1476,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ if (select_mode==SELECT_MULTI && p_mod.shift && selected_item && selected_item!=p_item) { bool inrange=false; - print_line("SELECT MULTI AND SHIFT AND ALL"); + select_single_item( p_item, root, col,selected_item,&inrange ); } else { select_single_item( p_item, root, col ); @@ -1490,7 +1499,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ /* editing */ - bool bring_up_editor=c.selected && already_selected; + bool bring_up_editor=c.selected;// && already_selected; bool bring_up_value_editor=false; String editor_text=c.text; @@ -1527,7 +1536,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ popup_menu->clear(); for (int i=0;i<c.text.get_slice_count(",");i++) { - String s = c.text.get_slice(",",i); + String s = c.text.get_slicec(',',i); popup_menu->add_item(s,i); } @@ -1605,31 +1614,14 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ return -1; - click_handled=true; + + click_handled=true; popup_edited_item=p_item; popup_edited_item_col=col; - text_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset ); - text_editor->set_size( Size2(col_width,item_h)); - text_editor->clear(); - text_editor->set_text( editor_text ); - text_editor->select_all(); - if (bring_up_value_editor) { - - value_editor->set_pos(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset+Point2i(0,text_editor->get_size().height) ); - value_editor->set_size( Size2(col_width,1)); - value_editor->show_modal(); - updating_value_editor=true; - value_editor->set_min( c.min ); - value_editor->set_max( c.max ); - value_editor->set_step( c.step ); - value_editor->set_val( c.val ); - value_editor->set_exp_unit_value( c.expr ); - updating_value_editor=false; - } - - text_editor->show_modal(); - text_editor->grab_focus(); + pressing_item_rect=Rect2(get_global_pos() + Point2i(col_ofs,_get_title_button_height()+y_ofs)-cache.offset,Size2(col_width,item_h)); + pressing_for_editor_text=editor_text; + pressing_for_editor=true; return -1; //select } else { @@ -2062,6 +2054,33 @@ void Tree::_input_event(InputEvent p_event) { update(); } + if (pressing_for_editor && popup_edited_item && popup_edited_item->get_cell_mode(popup_edited_item_col)==TreeItem::CELL_MODE_RANGE) { + //range drag + + if (!range_drag_enabled) { + + Vector2 cpos = Vector2(b.x,b.y); + if (cpos.distance_to(pressing_pos)>2) { + range_drag_enabled=true; + range_drag_capture_pos=cpos; + range_drag_base=popup_edited_item->get_range(popup_edited_item_col); + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + } + } else { + + TreeItem::Cell &c=popup_edited_item->cells[popup_edited_item_col]; + float diff_y = -b.relative_y; + diff_y=Math::pow(ABS(diff_y),1.8)*SGN(diff_y); + diff_y*=0.1; + range_drag_base=CLAMP(range_drag_base + c.step * diff_y, c.min, c.max); + + popup_edited_item->set_range(popup_edited_item_col,range_drag_base); + item_edited(popup_edited_item_col,popup_edited_item); + + } + + } + if (drag_touching && ! drag_touching_deaccel) { @@ -2084,6 +2103,31 @@ void Tree::_input_event(InputEvent p_event) { if (b.button_index==BUTTON_LEFT) { + if (pressing_for_editor) { + + if (range_drag_enabled) { + + range_drag_enabled=false; + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + warp_mouse(range_drag_capture_pos); + } else { + text_editor->set_pos(pressing_item_rect.pos); + text_editor->set_size(pressing_item_rect.size); + + text_editor->clear(); + text_editor->set_text( pressing_for_editor_text ); + text_editor->select_all(); + + text_editor->show_modal(); + text_editor->grab_focus(); + + } + pressing_for_editor=false; + + } + + + if (cache.click_type==Cache::CLICK_BUTTON) { emit_signal("button_pressed",cache.click_item,cache.click_column,cache.click_id); @@ -2145,11 +2189,15 @@ void Tree::_input_event(InputEvent p_event) { break; click_handled=false; + pressing_for_editor=false; blocked++; bool handled = propagate_mouse_event(pos+cache.offset,0,0,b.doubleclick,root,b.button_index,b.mod); blocked--; + if (pressing_for_editor) { + pressing_pos=Point2(b.x,b.y); + } if (drag_touching) { @@ -2234,7 +2282,7 @@ bool Tree::edit_selected() { popup_menu->clear(); for (int i=0;i<c.text.get_slice_count(",");i++) { - String s = c.text.get_slice(",",i); + String s = c.text.get_slicec(',',i); popup_menu->add_item(s,i); } @@ -2360,6 +2408,11 @@ void Tree::_notification(int p_what) { } } + if (p_what==NOTIFICATION_VISIBILITY_CHANGED) { + + drag_touching=false; + } + if (p_what==NOTIFICATION_ENTER_TREE) { update_cache();; @@ -2610,6 +2663,8 @@ void Tree::clear() { selected_item=NULL; edited_item=NULL; popup_edited_item=NULL; + selected_item=NULL; + pressing_for_editor=false; update(); }; @@ -3184,6 +3239,8 @@ Tree::Tree() { drag_speed=0; drag_touching=false; drag_touching_deaccel=false; + pressing_for_editor=false; + range_drag_enabled=false; } diff --git a/scene/gui/tree.h b/scene/gui/tree.h index f03827f542..3fbd7c95d9 100644 --- a/scene/gui/tree.h +++ b/scene/gui/tree.h @@ -258,7 +258,18 @@ friend class TreeItem; TreeItem *popup_edited_item; TreeItem *selected_item; TreeItem *edited_item; + + int pressed_button; + bool pressing_for_editor; + String pressing_for_editor_text; + Vector2 pressing_pos; + Rect2 pressing_item_rect; + + float range_drag_base; + bool range_drag_enabled; + Vector2 range_drag_capture_pos; + //TreeItem *cursor_item; //int cursor_column; @@ -454,6 +465,8 @@ public: void set_cursor_can_exit_tree(bool p_enable); bool can_cursor_exit_tree() const; + VScrollBar *get_vscroll_bar() { return v_scroll; } + Tree(); ~Tree(); 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_image.cpp b/scene/io/resource_format_image.cpp index 2663ac0762..f67d50b56c 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -31,9 +31,11 @@ #include "io/image_loader.h" #include "globals.h" #include "os/os.h" -RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_original_path) { - +RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; + if (p_path.extension()=="cube") { // open as cubemap txture @@ -83,6 +85,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina memdelete(f); cubemap->set_name(p_path.get_file()); + if (r_error) + *r_error=OK; return cubemap; @@ -112,6 +116,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina ERR_EXPLAIN("Failed loading image: "+p_path); ERR_FAIL_COND_V(err, RES()); + if (r_error) + *r_error=ERR_FILE_CORRUPT; #ifdef DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -180,6 +186,11 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina if (flags_found["tolinear"]) flags|=Texture::FLAG_CONVERT_TO_LINEAR; } + + if (flags_found.has("mirroredrepeat")) { + if (flags_found["mirroredrepeat"]) + flags|=Texture::FLAG_MIRRORED_REPEAT; + } if (debug_load_times) begtime=OS::get_singleton()->get_ticks_usec(); @@ -194,6 +205,9 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina print_line(" -make texture: "+rtos(total)); } + if (r_error) + *r_error=OK; + return RES( texture ); } diff --git a/scene/io/resource_format_image.h b/scene/io/resource_format_image.h index 1af65870f8..b5ec5a1200 100644 --- a/scene/io/resource_format_image.h +++ b/scene/io/resource_format_image.h @@ -40,7 +40,7 @@ class ResourceFormatLoaderImage : public ResourceFormatLoader { int max_texture_size; public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp index 7c90a4b3cd..00b800b28b 100644 --- a/scene/io/resource_format_wav.cpp +++ b/scene/io/resource_format_wav.cpp @@ -31,13 +31,18 @@ #include "scene/resources/sample.h" -RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderWAV::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; Error err; FileAccess *file=FileAccess::open(p_path, FileAccess::READ,&err); ERR_FAIL_COND_V( err!=OK, RES() ); + if (r_error) + *r_error=ERR_FILE_CORRUPT; + /* CHECK RIFF */ char riff[5]; riff[4]=0; @@ -244,6 +249,10 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_ file->close(); memdelete(file); + if (r_error) + *r_error=OK; + + return sample; } diff --git a/scene/io/resource_format_wav.h b/scene/io/resource_format_wav.h index 081a563d03..a74da041c1 100644 --- a/scene/io/resource_format_wav.h +++ b/scene/io/resource_format_wav.h @@ -33,7 +33,7 @@ class ResourceFormatLoaderWAV : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp new file mode 100644 index 0000000000..370eb1e74a --- /dev/null +++ b/scene/main/instance_placeholder.cpp @@ -0,0 +1,74 @@ +#include "instance_placeholder.h" + +#include "scene/resources/packed_scene.h" +#include "io/resource_loader.h" + +bool InstancePlaceholder::_set(const StringName& p_name, const Variant& p_value) { + + PropSet ps; + ps.name=p_name; + ps.value=p_value; + stored_values.push_back(ps); + return true; +} + +bool InstancePlaceholder::_get(const StringName& p_name,Variant &r_ret) const{ + + return false; +} +void InstancePlaceholder::_get_property_list( List<PropertyInfo> *p_list) const{ + + +} + + +void InstancePlaceholder::set_path(const String& p_name) { + + path=p_name; +} + +String InstancePlaceholder::get_path() const { + + return path; +} +void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene){ + + ERR_FAIL_COND(!is_inside_tree()); + + Node *base = get_parent(); + if (!base) + return; + + Ref<PackedScene> ps; + if (p_custom_scene.is_valid()) + ps = p_custom_scene; + else + ps = ResourceLoader::load(path,"PackedScene"); + + if (!ps.is_valid()) + return; + Node *scene = ps->instance(); + scene->set_name(get_name()); + int pos = get_position_in_parent(); + + for(List<PropSet>::Element *E=stored_values.front();E;E=E->next()) { + scene->set(E->get().name,E->get().value); + } + + queue_delete(); + + base->remove_child(this); + base->add_child(scene); + base->move_child(scene,pos); + +} + +void InstancePlaceholder::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("replace_by_instance","custom_scene:PackedScene"),&InstancePlaceholder::replace_by_instance,DEFVAL(Variant())); +} + +InstancePlaceholder::InstancePlaceholder() { + + +} diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h new file mode 100644 index 0000000000..e9e76e7a2d --- /dev/null +++ b/scene/main/instance_placeholder.h @@ -0,0 +1,37 @@ +#ifndef INSTANCE_PLACEHOLDER_H +#define INSTANCE_PLACEHOLDER_H + +#include "scene/main/node.h" + +class PackedScene; + +class InstancePlaceholder : public Node { + + OBJ_TYPE(InstancePlaceholder,Node); + + String path; + struct PropSet { + StringName name; + Variant value; + }; + + List<PropSet> stored_values; + +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(); + +public: + + void set_path(const String& p_name); + String get_path() const; + + void replace_by_instance(const Ref<PackedScene>& p_custom_scene=Ref<PackedScene>()); + + InstancePlaceholder(); +}; + +#endif // INSTANCE_PLACEHOLDER_H diff --git a/scene/main/node.cpp b/scene/main/node.cpp index ab530866bb..631dc8dcc7 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -196,6 +196,14 @@ void Node::_propagate_enter_tree() { } data.blocked--; + +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && data.filename!=String()) { + //used for live edit + data.tree->live_scene_edit_cache[data.filename].insert(this); + } +#endif // enter groups } @@ -205,6 +213,28 @@ void Node::_propagate_exit_tree() { //block while removing children +#ifdef DEBUG_ENABLED + + if (ScriptDebugger::get_singleton() && data.filename!=String()) { + //used for live edit + Map<String,Set<Node*> >::Element *E=data.tree->live_scene_edit_cache.find(data.filename); + if (E) { + E->get().erase(this); + if (E->get().size()==0) { + data.tree->live_scene_edit_cache.erase(E); + } + } + + Map<Node*,Map<ObjectID,Node*> >::Element *F=data.tree->live_edit_remove_list.find(this); + if (F) { + for (Map<ObjectID,Node*>::Element*G=F->get().front();G;G=G->next()) { + + memdelete(G->get()); + } + data.tree->live_edit_remove_list.erase(F); + } + } +#endif data.blocked++; for (int i=data.children.size()-1;i>=0;i--) { @@ -552,6 +582,52 @@ void Node::set_human_readable_collision_renaming(bool p_enabled) { } + +String Node::validate_child_name(const String& p_name) const { + + //this approach to autoset node names is human readable but very slow + //it's turned on while running in the editor + + String basename = p_name; + + if (basename==String()) { + + return String(); + } + + int val=1; + + for(;;) { + + String attempted = val > 1 ? (basename + " " +itos(val) ) : basename; + + bool found=false; + + for (int i=0;i<data.children.size();i++) { + + //if (data.children[i]==p_child) + // continue; + if (data.children[i]->get_name() == attempted) { + found=true; + break; + } + + } + + if (found) { + + val++; + continue; + } + + return attempted; + break; + } + + return basename; + +} + void Node::_validate_child_name(Node *p_child) { /* Make sure the name is unique */ @@ -641,6 +717,7 @@ void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) { p_child->data.pos=data.children.size(); data.children.push_back( p_child ); p_child->data.parent=this; + p_child->notification(NOTIFICATION_PARENTED); if (data.tree) { p_child->_set_tree(data.tree); @@ -649,7 +726,6 @@ void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) { /* Notify */ //recognize childs created in this node constructor p_child->data.parent_owned=data.in_constructor; - p_child->notification(NOTIFICATION_PARENTED); add_child_notify(p_child); @@ -765,6 +841,20 @@ Node *Node::get_child(int p_index) const { return data.children[p_index]; } + +Node *Node::_get_child_by_name(const StringName& p_name) const { + + int cc=data.children.size(); + Node* const* cd=data.children.ptr(); + + for(int i=0;i<cc;i++){ + if (cd[i]->data.name==p_name) + return cd[i]; + } + + return NULL; +} + Node *Node::_get_node(const NodePath& p_path) const { ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL ); @@ -830,8 +920,10 @@ Node *Node::_get_node(const NodePath& p_path) const { Node *Node::get_node(const NodePath& p_path) const { Node *node = _get_node(p_path); - ERR_EXPLAIN("Node not found: "+p_path); - ERR_FAIL_COND_V(!node,NULL); + if (!node) { + ERR_EXPLAIN("Node not found: "+p_path); + ERR_FAIL_COND_V(!node,NULL); + } return node; } @@ -960,6 +1052,7 @@ void Node::get_owned_by(Node *p_by,List<Node*> *p_owned) { void Node::_set_owner_nocheck(Node* p_owner) { + ERR_FAIL_COND(data.owner); data.owner=p_owner; data.owner->data.owned.push_back( this ); data.OW = data.owner->data.owned.back(); @@ -1256,7 +1349,29 @@ String Node::get_filename() const { return data.filename; } +void Node::set_editable_instance(Node* p_node,bool p_editable) { + + ERR_FAIL_NULL(p_node); + ERR_FAIL_COND(!is_a_parent_of(p_node)); + NodePath p = get_path_to(p_node); + if (!p_editable) + data.editable_instances.erase(p); + else + data.editable_instances[p]=true; + +} + +bool Node::is_editable_instance(Node *p_node) const { + + if (!p_node) + return false; //easier, null is never editable :) + ERR_FAIL_COND_V(!is_a_parent_of(p_node),false); + NodePath p = get_path_to(p_node); + return data.editable_instances.has(p); +} + +#if 0 void Node::generate_instance_state() { @@ -1307,13 +1422,36 @@ Dictionary Node::get_instance_state() const { return data.instance_state; } -Vector<StringName> Node::get_instance_groups() const { +#endif + +void Node::set_scene_instance_state(const Ref<SceneState>& p_state) { - return data.instance_groups; + data.instance_state=p_state; } -Vector<Node::Connection> Node::get_instance_connections() const{ - return data.instance_connections; +Ref<SceneState> Node::get_scene_instance_state() const{ + + return data.instance_state; +} + +void Node::set_scene_inherited_state(const Ref<SceneState>& p_state) { + + data.inherited_state=p_state; +} + +Ref<SceneState> Node::get_scene_inherited_state() const{ + + return data.inherited_state; +} + +void Node::set_scene_instance_load_placeholder(bool p_enable) { + + data.use_placeholder=p_enable; +} + +bool Node::get_scene_instance_load_placeholder() const{ + + return data.use_placeholder; } int Node::get_position_in_parent() const { @@ -1323,18 +1461,31 @@ int Node::get_position_in_parent() const { -Node *Node::duplicate() const { +Node *Node::duplicate(bool p_use_instancing) const { Node *node=NULL; - Object *obj = ObjectTypeDB::instance(get_type()); - ERR_FAIL_COND_V(!obj,NULL); - node = obj->cast_to<Node>(); - if (!node) - memdelete(obj); - ERR_FAIL_COND_V(!node,NULL); + bool instanced=false; + + if (p_use_instancing && get_filename()!=String()) { + + Ref<PackedScene> res = ResourceLoader::load(get_filename()); + ERR_FAIL_COND_V(res.is_null(),NULL); + node=res->instance(); + ERR_FAIL_COND_V(!node,NULL); + + instanced=true; + + } else { + Object *obj = ObjectTypeDB::instance(get_type()); + ERR_FAIL_COND_V(!obj,NULL); + node = obj->cast_to<Node>(); + if (!node) + memdelete(obj); + ERR_FAIL_COND_V(!node,NULL); + } if (get_filename()!="") { //an instance @@ -1360,7 +1511,10 @@ Node *Node::duplicate() const { if (get_child(i)->data.parent_owned) continue; - Node *dup = get_child(i)->duplicate(); + if (instanced && get_child(i)->data.owner==this) + continue; //part of instance + + Node *dup = get_child(i)->duplicate(p_use_instancing); if (!dup) { memdelete(node); @@ -1816,6 +1970,16 @@ void Node::get_argument_options(const StringName& p_function,int p_idx,List<Stri Object::get_argument_options(p_function,p_idx,r_options); } + +void Node::clear_internal_tree_resource_paths() { + + clear_internal_resource_paths(); + for(int i=0;i<data.children.size();i++) { + data.children[i]->clear_internal_tree_resource_paths(); + } + +} + void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_name","name"),&Node::set_name); @@ -1829,7 +1993,7 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("has_node","path"),&Node::has_node); ObjectTypeDB::bind_method(_MD("get_node:Node","path"),&Node::get_node); ObjectTypeDB::bind_method(_MD("get_parent:Parent"),&Node::get_parent); - ObjectTypeDB::bind_method(_MD("find_node:Node","mask","recursive","owned"),&Node::get_node,DEFVAL(true),DEFVAL(true)); + ObjectTypeDB::bind_method(_MD("find_node:Node","mask","recursive","owned"),&Node::find_node,DEFVAL(true),DEFVAL(true)); ObjectTypeDB::bind_method(_MD("has_node_and_resource","path"),&Node::has_node_and_resource); ObjectTypeDB::bind_method(_MD("get_node_and_resource","path"),&Node::_get_node_and_resource); @@ -1872,7 +2036,7 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tree:SceneTree"),&Node::get_tree); - ObjectTypeDB::bind_method(_MD("duplicate:Node"),&Node::duplicate); + ObjectTypeDB::bind_method(_MD("duplicate:Node","use_instancing"),&Node::duplicate,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("replace_by","node:Node","keep_data"),&Node::replace_by,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("get_viewport"),&Node::get_viewport); @@ -1881,7 +2045,7 @@ void Node::_bind_methods() { #ifdef TOOLS_ENABLED ObjectTypeDB::bind_method(_MD("_set_import_path","import_path"),&Node::set_import_path); ObjectTypeDB::bind_method(_MD("_get_import_path"),&Node::get_import_path); - ADD_PROPERTY( PropertyInfo(Variant::NODE_PATH,"_import_path",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_import_path"),_SCS("_get_import_path")); + ADD_PROPERTYNZ( PropertyInfo(Variant::NODE_PATH,"_import_path",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_import_path"),_SCS("_get_import_path")); #endif @@ -1947,6 +2111,7 @@ Node::Node() { data.parent_owned=false; data.in_constructor=true; data.viewport=NULL; + data.use_placeholder=false; } Node::~Node() { @@ -1963,3 +2128,4 @@ Node::~Node() { } +//////////////////////////////// diff --git a/scene/main/node.h b/scene/main/node.h index a89a6abf33..87fa4dd6ca 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -38,6 +38,7 @@ class Viewport; +class SceneState; class Node : public Object { OBJ_TYPE( Node, Object ); @@ -69,9 +70,10 @@ private: struct Data { String filename; - Dictionary instance_state; - Vector<StringName> instance_groups; - Vector<Connection> instance_connections; + Ref<SceneState> instance_state; + Ref<SceneState> inherited_state; + + HashMap<NodePath,int> editable_instances; Node *parent; Node *owner; @@ -96,6 +98,7 @@ private: PauseMode pause_mode; Node *pause_owner; // variables used to properly sort the node when processing, ignored otherwise + //should move all the stuff below to bits bool fixed_process; bool idle_process; @@ -105,6 +108,9 @@ private: bool parent_owned; bool in_constructor; + bool use_placeholder; + + } data; @@ -112,6 +118,7 @@ private: virtual bool _use_builtin_script() const { return true; } Node *_get_node(const NodePath& p_path) const; + Node *_get_child_by_name(const StringName& p_name) const; @@ -151,7 +158,7 @@ protected: static void _bind_methods(); -friend class PackedScene; +friend class SceneState; void _add_child_nocheck(Node* p_child,const StringName& p_name); void _set_owner_nocheck(Node* p_owner); @@ -208,7 +215,7 @@ public: struct GroupInfo { - String name; + StringName name; bool persistent; }; @@ -229,7 +236,11 @@ public: void set_filename(const String& p_filename); String get_filename() const; - + + void set_editable_instance(Node* p_node,bool p_editable); + bool is_editable_instance(Node* p_node) const; + + /* NOTIFICATIONS */ void propagate_notification(int p_notification); @@ -255,15 +266,20 @@ public: int get_position_in_parent() const; - Node *duplicate() const; + Node *duplicate(bool p_use_instancing=false) const; Node *duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const; + //Node *clone_tree() const; // used by editors, to save what has changed only - void generate_instance_state(); - Dictionary get_instance_state() const; - Vector<StringName> get_instance_groups() const; - Vector<Connection> get_instance_connections() const; + void set_scene_instance_state(const Ref<SceneState>& p_state); + Ref<SceneState> get_scene_instance_state() const; + + void set_scene_inherited_state(const Ref<SceneState>& p_state); + Ref<SceneState> get_scene_inherited_state() const; + + void set_scene_instance_load_placeholder(bool p_enable); + bool get_scene_instance_load_placeholder() const; static Vector<Variant> make_binds(VARIANT_ARG_LIST); @@ -275,6 +291,8 @@ public: static void print_stray_nodes(); + String validate_child_name(const String& p_name) const; + void queue_delete(); //shitty hacks for speed @@ -290,6 +308,8 @@ public: void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; + void clear_internal_tree_resource_paths(); + _FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; } /* CANVAS */ @@ -302,6 +322,4 @@ public: typedef Set<Node*,Node::Comparator> NodeSet; - - #endif diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index 584b40337f..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) @@ -1044,7 +1214,371 @@ void SceneTree::add_current_scene(Node * p_current) { current_scene=p_current; root->add_child(p_current); } +#ifdef DEBUG_ENABLED + +void SceneTree::_live_edit_node_path_func(const NodePath &p_path,int p_id) { + + live_edit_node_path_cache[p_id]=p_path; +} + +void SceneTree::_live_edit_res_path_func(const String &p_path,int p_id) { + + live_edit_resource_cache[p_id]=p_path; +} + +void SceneTree::_live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->set(p_prop,p_value); + } + +} + +void SceneTree::_live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_node_set_func(p_id,p_prop,r); + +} +void SceneTree::_live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + if (!live_edit_node_path_cache.has(p_id)) + return; + + NodePath np = live_edit_node_path_cache[p_id]; + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(np)) + continue; + Node *n2 = n->get_node(np); + + n2->call(p_method,VARIANT_ARG_PASS); + } +} +void SceneTree::_live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->set(p_prop,p_value); +} +void SceneTree::_live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) { + + RES r = ResourceLoader::load(p_value); + if (!r.is_valid()) + return; + _live_edit_res_set_func(p_id,p_prop,r); + +} +void SceneTree::_live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { + + if (!live_edit_resource_cache.has(p_id)) + return; + + String resp = live_edit_resource_cache[p_id]; + + if (!ResourceCache::has(resp)) + return; + + RES r = ResourceCache::get(resp); + if (!r.is_valid()) + return; + + r->call(p_method,VARIANT_ARG_PASS); +} + +void SceneTree::_live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) { + + live_edit_root=p_scene_path; + live_edit_scene=p_scene_from; +} + +void SceneTree::_live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name) { + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + Object *o = ObjectTypeDB::instance(p_type); + if (!o) + continue; + Node *no=o->cast_to<Node>(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name){ + + Ref<PackedScene> ps = ResourceLoader::load(p_path); + + if (!ps.is_valid()) + return; + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_parent)) + continue; + Node *n2 = n->get_node(p_parent); + + + + Node *no=ps->instance(); + no->set_name(p_name); + + n2->add_child(no); + } +} +void SceneTree::_live_edit_remove_node_func(const NodePath& p_at){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;) { + + Set<Node*>::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + memdelete(n2); + + F=N; + + } +} +void SceneTree::_live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + + for(Set<Node*>::Element *F=E->get().front();F;) { + + Set<Node*>::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + + Node *n2 = n->get_node(p_at); + + n2->get_parent()->remove_child(n2); + + live_edit_remove_list[n][p_keep_id]=n2; + + F=N; + + } +} +void SceneTree::_live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos){ + + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;) { + + Set<Node*>::Element *N=F->next(); + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Map<Node*,Map<ObjectID,Node*> >::Element *EN=live_edit_remove_list.find(n); + + if (!EN) + continue; + + Map<ObjectID,Node*>::Element *FN=EN->get().find(p_id); + + if (!FN) + continue; + n2->add_child(FN->get()); + + EN->get().erase(FN); + + if (EN->get().size()==0) { + live_edit_remove_list.erase(EN); + } + + F=N; + + } +} +void SceneTree::_live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *n2 = n->get_node(p_at); + + Node *dup = n2->duplicate(true); + + if (!dup) + continue; + + dup->set_name(p_new_name); + n2->get_parent()->add_child(dup); + + } +} +void SceneTree::_live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos){ + + Node *base = NULL; + if (root->has_node(live_edit_root)) + base = root->get_node(live_edit_root); + + Map<String,Set<Node*> >::Element *E=live_scene_edit_cache.find(live_edit_scene); + if (!E) + return; //scene not editable + + for(Set<Node*>::Element *F=E->get().front();F;F=F->next()) { + + Node *n=F->get(); + + if (base && !base->is_a_parent_of(n)) + continue; + + if (!n->has_node(p_at)) + continue; + Node *nfrom = n->get_node(p_at); + + if (!n->has_node(p_new_place)) + continue; + Node *nto = n->get_node(p_new_place); + + nfrom->get_parent()->remove_child(nfrom); + nfrom->set_name(p_new_name); + + nto->add_child(nfrom); + if (p_at_pos>=0) + nto->move_child(nfrom,p_at_pos); + + } +} + + +#endif void SceneTree::_bind_methods() { @@ -1060,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); @@ -1108,6 +1647,9 @@ void SceneTree::_bind_methods() { ADD_SIGNAL( MethodInfo("node_removed",PropertyInfo( Variant::OBJECT, "node") ) ); ADD_SIGNAL( MethodInfo("screen_resized") ); + ADD_SIGNAL( MethodInfo("idle_frame")); + ADD_SIGNAL( MethodInfo("fixed_frame")); + BIND_CONSTANT( GROUP_CALL_DEFAULT ); BIND_CONSTANT( GROUP_CALL_REVERSE ); BIND_CONSTANT( GROUP_CALL_REALTIME ); @@ -1123,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; @@ -1166,8 +1721,36 @@ SceneTree::SceneTree() { edited_scene_root=NULL; #endif - ADD_SIGNAL( MethodInfo("idle_frame")); - ADD_SIGNAL( MethodInfo("fixed_frame")); +#ifdef DEBUG_ENABLED + + + live_edit_funcs.udata=this; + live_edit_funcs.node_path_func=_live_edit_node_path_funcs; + live_edit_funcs.res_path_func=_live_edit_res_path_funcs; + live_edit_funcs.node_set_func=_live_edit_node_set_funcs; + live_edit_funcs.node_set_res_func=_live_edit_node_set_res_funcs; + live_edit_funcs.node_call_func=_live_edit_node_call_funcs; + live_edit_funcs.res_set_func=_live_edit_res_set_funcs; + live_edit_funcs.res_set_res_func=_live_edit_res_set_res_funcs; + live_edit_funcs.res_call_func=_live_edit_res_call_funcs; + live_edit_funcs.root_func=_live_edit_root_funcs; + + live_edit_funcs.tree_create_node_func=_live_edit_create_node_funcs; + live_edit_funcs.tree_instance_node_func=_live_edit_instance_node_funcs; + live_edit_funcs.tree_remove_node_func=_live_edit_remove_node_funcs; + live_edit_funcs.tree_remove_and_keep_node_func=_live_edit_remove_and_keep_node_funcs; + live_edit_funcs.tree_restore_node_func=_live_edit_restore_node_funcs; + live_edit_funcs.tree_duplicate_node_func=_live_edit_duplicate_node_funcs; + live_edit_funcs.tree_reparent_node_func=_live_edit_reparent_node_funcs; + + if (ScriptDebugger::get_singleton()) { + ScriptDebugger::get_singleton()->set_live_edit_funcs(&live_edit_funcs); + } + + live_edit_root=NodePath("/root"); + +#endif + } diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index e49c150fbf..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(); @@ -164,6 +179,58 @@ friend class Viewport; SelfList<Node>::List xform_change_list; +#ifdef DEBUG_ENABLED + + Map<int,NodePath> live_edit_node_path_cache; + Map<int,String> live_edit_resource_cache; + + NodePath live_edit_root; + String live_edit_scene; + + Map<String,Set<Node*> > live_scene_edit_cache; + Map<Node*,Map<ObjectID,Node*> > live_edit_remove_list; + + ScriptDebugger::LiveEditFuncs live_edit_funcs; + + void _live_edit_node_path_func(const NodePath &p_path,int p_id) ; + void _live_edit_res_path_func(const String &p_path,int p_id) ; + + void _live_edit_node_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ; + void _live_edit_node_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ; + void _live_edit_node_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ; + void _live_edit_res_set_func(int p_id,const StringName& p_prop,const Variant& p_value) ; + void _live_edit_res_set_res_func(int p_id,const StringName& p_prop,const String& p_value) ; + void _live_edit_res_call_func(int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) ; + void _live_edit_root_func(const NodePath& p_scene_path,const String& p_scene_from) ; + + void _live_edit_create_node_func(const NodePath& p_parent,const String& p_type,const String& p_name); + void _live_edit_instance_node_func(const NodePath& p_parent,const String& p_path,const String& p_name); + void _live_edit_remove_node_func(const NodePath& p_at); + void _live_edit_remove_and_keep_node_func(const NodePath& p_at,ObjectID p_keep_id); + void _live_edit_restore_node_func(ObjectID p_id,const NodePath& p_at,int p_at_pos); + void _live_edit_duplicate_node_func(const NodePath& p_at,const String& p_new_name); + void _live_edit_reparent_node_func(const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos); + + static void _live_edit_node_path_funcs(void *self,const NodePath &p_path,int p_id) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_path_func(p_path,p_id); } + static void _live_edit_res_path_funcs(void *self,const String &p_path,int p_id) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_path_func(p_path,p_id); } + + static void _live_edit_node_set_funcs(void *self,int p_id,const StringName& p_prop,const Variant& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_set_func(p_id,p_prop,p_value); } + static void _live_edit_node_set_res_funcs(void *self,int p_id,const StringName& p_prop,const String& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_set_res_func(p_id,p_prop,p_value); } + static void _live_edit_node_call_funcs(void *self,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree*>(self)->_live_edit_node_call_func(p_id,p_method,VARIANT_ARG_PASS); } + static void _live_edit_res_set_funcs(void *self,int p_id,const StringName& p_prop,const Variant& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_set_func(p_id,p_prop,p_value); } + static void _live_edit_res_set_res_funcs(void *self,int p_id,const StringName& p_prop,const String& p_value) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_set_res_func(p_id,p_prop,p_value); } + static void _live_edit_res_call_funcs(void *self,int p_id,const StringName& p_method,VARIANT_ARG_DECLARE) { reinterpret_cast<SceneTree*>(self)->_live_edit_res_call_func(p_id,p_method,VARIANT_ARG_PASS); } + static void _live_edit_root_funcs(void *self, const NodePath& p_scene_path,const String& p_scene_from) { reinterpret_cast<SceneTree*>(self)->_live_edit_root_func(p_scene_path,p_scene_from); } + + static void _live_edit_create_node_funcs(void* self,const NodePath& p_parent,const String& p_type,const String& p_name) { reinterpret_cast<SceneTree*>(self)->_live_edit_create_node_func(p_parent,p_type,p_name); } + static void _live_edit_instance_node_funcs(void* self,const NodePath& p_parent,const String& p_path,const String& p_name) { reinterpret_cast<SceneTree*>(self)->_live_edit_instance_node_func(p_parent,p_path,p_name); } + static void _live_edit_remove_node_funcs(void* self,const NodePath& p_at) { reinterpret_cast<SceneTree*>(self)->_live_edit_remove_node_func(p_at); } + static void _live_edit_remove_and_keep_node_funcs(void* self,const NodePath& p_at,ObjectID p_keep_id) { reinterpret_cast<SceneTree*>(self)->_live_edit_remove_and_keep_node_func(p_at,p_keep_id); } + static void _live_edit_restore_node_funcs(void* self,ObjectID p_id,const NodePath& p_at,int p_at_pos) { reinterpret_cast<SceneTree*>(self)->_live_edit_restore_node_func(p_id,p_at,p_at_pos); } + static void _live_edit_duplicate_node_funcs(void* self,const NodePath& p_at,const String& p_new_name) { reinterpret_cast<SceneTree*>(self)->_live_edit_duplicate_node_func(p_at,p_new_name); } + static void _live_edit_reparent_node_funcs(void* self,const NodePath& p_at,const NodePath& p_new_place,const String& p_new_name,int p_at_pos) { reinterpret_cast<SceneTree*>(self)->_live_edit_reparent_node_func(p_at,p_new_place,p_new_name,p_at_pos); } + +#endif protected: void _notification(int p_notification); @@ -218,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; @@ -245,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 717ed93b16..fe6b192d78 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -36,6 +36,7 @@ #include "resources/default_theme/default_theme.h" #include "object_type_db.h" #include "scene/main/canvas_layer.h" +#include "scene/main/instance_placeholder.h" #include "scene/main/viewport.h" #include "scene/gui/control.h" #include "scene/gui/texture_progress.h" @@ -52,6 +53,7 @@ #include "scene/gui/option_button.h" #include "scene/gui/color_picker.h" #include "scene/gui/texture_frame.h" +#include "scene/gui/patch_9_frame.h" #include "scene/gui/menu_button.h" #include "scene/gui/check_box.h" #include "scene/gui/check_button.h" @@ -215,7 +217,7 @@ #include "scene/3d/collision_polygon.h" #endif - +#include "scene/resources/scene_format_text.h" static ResourceFormatLoaderImage *resource_loader_image=NULL; static ResourceFormatLoaderWAV *resource_loader_wav=NULL; @@ -228,6 +230,8 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL; static ResourceFormatLoaderTheme *resource_loader_theme=NULL; static ResourceFormatLoaderShader *resource_loader_shader=NULL; +static ResourceFormatSaverText *resource_saver_text=NULL; + //static SceneStringNames *string_names; void register_scene_types() { @@ -266,6 +270,7 @@ void register_scene_types() { ObjectTypeDB::register_type<Object>(); ObjectTypeDB::register_type<Node>(); + ObjectTypeDB::register_virtual_type<InstancePlaceholder>(); ObjectTypeDB::register_type<Viewport>(); ObjectTypeDB::register_virtual_type<RenderTargetTexture>(); @@ -302,6 +307,7 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init ObjectTypeDB::register_type<TextureFrame>(); + ObjectTypeDB::register_type<Patch9Frame>(); ObjectTypeDB::register_type<TabContainer>(); ObjectTypeDB::register_type<Tabs>(); ObjectTypeDB::register_virtual_type<Separator>(); @@ -456,7 +462,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); @@ -490,9 +495,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 @@ -576,7 +584,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 @@ -607,6 +616,9 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init + resource_saver_text = memnew( ResourceFormatSaverText ); + ResourceSaver::add_resource_format_saver(resource_saver_text); + } void unregister_scene_types() { @@ -624,5 +636,9 @@ void unregister_scene_types() { memdelete( resource_loader_theme ); memdelete( resource_loader_shader ); + + if (resource_saver_text) { + memdelete(resource_saver_text); + } SceneStringNames::free(); } diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 095406dad9..afd4dc5304 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -42,8 +42,8 @@ bool Animation::_set(const StringName& p_name, const Variant& p_value) { set_step(p_value); else if (name.begins_with("tracks/")) { - int track=name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int track=name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); if (tracks.size()==track && what=="type") { @@ -257,8 +257,8 @@ bool Animation::_get(const StringName& p_name,Variant &r_ret) const { r_ret= step; else if (name.begins_with("tracks/")) { - int track=name.get_slice("/",1).to_int(); - String what=name.get_slice("/",2); + int track=name.get_slicec('/',1).to_int(); + String what=name.get_slicec('/',2); ERR_FAIL_INDEX_V( track, tracks.size(), false ); if (what=="type") { @@ -1718,7 +1718,7 @@ void Animation::clear() { -bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) { +bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle,const Vector3& p_norm) { real_t c = (t1.time-t0.time)/(t2.time-t0.time); @@ -1754,6 +1754,9 @@ bool Animation::_transform_track_optimize_key(const TKey<TransformKey> &t0,const return false; //beyond allowed error for colinearity } + if (p_norm!=Vector3() && Math::acos(pd.normalized().dot(p_norm))>p_alowed_angular_err) + return false; + t[0] = (d1-d0)/(d2-d0); } } @@ -1905,16 +1908,21 @@ void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,fl bool prev_erased=false; TKey<TransformKey> first_erased; + Vector3 norm; + for(int i=1;i<tt->transforms.size()-1;i++) { TKey<TransformKey> &t0 = tt->transforms[i-1]; TKey<TransformKey> &t1 = tt->transforms[i]; TKey<TransformKey> &t2 = tt->transforms[i+1]; - bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle); + bool erase = _transform_track_optimize_key(t0,t1,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle,norm); + if (erase && !prev_erased) { + norm=(t2.value.loc-t1.value.loc).normalized(); + } - if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle)) { + if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle,norm)) { //avoid error to go beyond first erased key erase=false; } @@ -1932,9 +1940,11 @@ void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,fl } else { prev_erased=false; + norm=Vector3(); } + // print_line(itos(i)+" could be eliminated: "+rtos(tr)); //} } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index d4042646fb..256826a4bb 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -204,7 +204,7 @@ private: return idxr; } - bool _transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle); + bool _transform_track_optimize_key(const TKey<TransformKey> &t0,const TKey<TransformKey> &t1, const TKey<TransformKey> &t2, float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle,const Vector3& p_norm); void _transform_track_optimize(int p_idx, float p_allowed_err=0.05, float p_alowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125); protected: 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/baked_light.cpp b/scene/resources/baked_light.cpp index 226edec9ae..31282a0274 100644 --- a/scene/resources/baked_light.cpp +++ b/scene/resources/baked_light.cpp @@ -311,11 +311,11 @@ bool BakedLight::_set(const StringName& p_name, const Variant& p_value) { String n = p_name; if (!n.begins_with("lightmap")) return false; - int idx = n.get_slice("/",1).to_int(); + int idx = n.get_slicec('/',1).to_int(); ERR_FAIL_COND_V(idx<0,false); ERR_FAIL_COND_V(idx>lightmaps.size(),false); - String what = n.get_slice("/",2); + String what = n.get_slicec('/',2); Ref<Texture> tex; Size2 gens; @@ -343,11 +343,11 @@ bool BakedLight::_get(const StringName& p_name,Variant &r_ret) const{ String n = p_name; if (!n.begins_with("lightmap")) return false; - int idx = n.get_slice("/",1).to_int(); + int idx = n.get_slicec('/',1).to_int(); ERR_FAIL_COND_V(idx<0,false); ERR_FAIL_COND_V(idx>lightmaps.size(),false); - String what = n.get_slice("/",2); + String what = n.get_slicec('/',2); if (what=="texture") { if (idx==lightmaps.size()) diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index ef056a6230..9a6452797a 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -205,7 +205,10 @@ BitMap::BitMap() { ////////////////////////////////////// -RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderBitMap::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; BitMap* ptr = memnew(BitMap); Ref<BitMap> bitmap( ptr ); @@ -219,6 +222,8 @@ RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_origin ERR_FAIL_COND_V(err, RES()); bitmap->create_from_image_alpha(image); + if (r_error) + *r_error=OK; return bitmap; diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h index 29b7bc66f4..a6b29bb919 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_mask.h @@ -66,7 +66,7 @@ class ResourceFormatLoaderBitMap : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; 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/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index 2267cc9e2f..f1e97fd626 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -250,7 +250,6 @@ void make_default_theme() { t->set_stylebox("hover","ToolButton", make_stylebox( button_normal_png,4,4,4,4) ); t->set_stylebox("disabled","ToolButton", make_empty_stylebox(4,4,4,4) ); t->set_stylebox("focus","ToolButton", focus ); - t->set_font("font","ToolButton", default_font ); t->set_color("font_color","ToolButton", control_font_color ); @@ -298,7 +297,7 @@ void make_default_theme() { t->set_color("font_color_hover","MenuButton", control_font_color_hover ); t->set_color("font_color_disabled","MenuButton", Color(1,1,1,0.3) ); - t->set_constant("hseparation","MenuButton", 0 ); + t->set_constant("hseparation","MenuButton", 3 ); // CheckBox @@ -655,6 +654,8 @@ void make_default_theme() { t->set_icon("increment_hilite","TabContainer",make_icon( scroll_button_right_hl_png)); t->set_icon("decrement","TabContainer",make_icon( scroll_button_left_png)); t->set_icon("decrement_hilite","TabContainer",make_icon( scroll_button_left_hl_png)); + t->set_icon("menu","TabContainer",make_icon( tab_menu_png)); + t->set_icon("menu_hilite","TabContainer",make_icon( tab_menu_hl_png)); t->set_font("font","TabContainer", default_font ); @@ -674,6 +675,9 @@ void make_default_theme() { t->set_stylebox("tab_fg","Tabs", make_stylebox( tab_current_png,4,4,4,4,16,4,16,4) ); t->set_stylebox("tab_bg","Tabs", make_stylebox( tab_behind_png,4,4,4,4,16,6,16,4) ); t->set_stylebox("panel","Tabs", make_stylebox( tab_container_bg_png,4,4,4,4) ); + t->set_stylebox("button_pressed","Tabs", make_stylebox( button_pressed_png,4,4,4,4) ); + t->set_stylebox("button","Tabs", make_stylebox( button_normal_png,4,4,4,4) ); + t->set_font("font","Tabs", default_font ); diff --git a/scene/resources/default_theme/selection.png b/scene/resources/default_theme/selection.png Binary files differindex 074c7a4d80..3b1c810c40 100644 --- a/scene/resources/default_theme/selection.png +++ b/scene/resources/default_theme/selection.png diff --git a/scene/resources/default_theme/selection_oof.png b/scene/resources/default_theme/selection_oof.png Binary files differindex 17ec977bd6..e8680128cd 100644 --- a/scene/resources/default_theme/selection_oof.png +++ b/scene/resources/default_theme/selection_oof.png diff --git a/scene/resources/default_theme/tab_menu.png b/scene/resources/default_theme/tab_menu.png Binary files differnew file mode 100644 index 0000000000..c5659da11b --- /dev/null +++ b/scene/resources/default_theme/tab_menu.png diff --git a/scene/resources/default_theme/tab_menu_hl.png b/scene/resources/default_theme/tab_menu_hl.png Binary files differnew file mode 100644 index 0000000000..6f68502c07 --- /dev/null +++ b/scene/resources/default_theme/tab_menu_hl.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 8bd0a66271..03d851e749 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -340,12 +340,12 @@ static const unsigned char scroll_grabber_hl_png[]={ static const unsigned char selection_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0xff,0x0,0xff,0x0,0xff,0xa0,0xbd,0xa7,0x93,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x11,0x12,0x2a,0x16,0x85,0x48,0x8b,0x13,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xba,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0x93,0x31,0xa,0xc2,0x50,0x10,0x44,0xdf,0x97,0xbf,0x8a,0x3f,0x45,0xd0,0x52,0xbb,0xfc,0x63,0x88,0x88,0xa7,0xd0,0x23,0x9a,0x63,0x84,0x90,0x63,0x24,0x9d,0x9d,0x60,0x95,0x2f,0xb2,0x21,0x5a,0x18,0xb4,0x52,0x3,0x69,0x2c,0x9c,0x6e,0x8b,0x99,0xd9,0x59,0x76,0xc,0x30,0x6,0xa6,0xc0,0x4,0x18,0xd1,0xf,0x2d,0x70,0x5,0x2e,0xb6,0x23,0x2f,0x81,0x19,0x20,0x3d,0x5,0x14,0x38,0x3,0x47,0xdb,0x39,0xcf,0xd7,0xab,0xcd,0xc2,0x27,0xfe,0x20,0x22,0xe6,0x23,0x53,0xf5,0x56,0x56,0xe5,0x3e,0x2f,0x32,0x3,0x9c,0x6c,0xb7,0xb6,0xf5,0x89,0x4f,0x43,0x8,0xd4,0x21,0x7c,0xb4,0x8e,0x9c,0x33,0x3e,0xf1,0x69,0x5e,0x64,0x5b,0x60,0xf4,0xcc,0x2c,0x22,0x5f,0xc9,0x0,0x75,0x8,0x88,0xbc,0x92,0xf6,0x3d,0xda,0x5b,0xfc,0x5,0x7e,0x4a,0x40,0x55,0x89,0x9c,0xfb,0x4a,0x88,0x9c,0x43,0x55,0x9f,0xb3,0xe5,0x51,0x8c,0xa6,0xac,0xca,0x9d,0x4f,0xfc,0x21,0x8e,0xe3,0x5e,0xaf,0xc,0x34,0x40,0x6b,0x80,0x98,0x1,0x65,0x32,0xc,0xac,0xf3,0x1d,0x55,0xc6,0x3e,0x2,0xe2,0x2e,0xc9,0xc8,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x15,0x0,0x15,0x0,0x17,0xc8,0x7d,0x47,0xd1,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x6,0x14,0x14,0x31,0x1a,0x5f,0x97,0xc4,0x56,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0xa3,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x93,0xbd,0xa,0xc2,0x40,0x10,0x84,0xbf,0xbb,0x6c,0x72,0x8,0x1,0x51,0x4b,0xdf,0x23,0xc9,0xfb,0x57,0x12,0x9f,0x43,0xb0,0x10,0x2c,0x14,0xe4,0x92,0xcb,0xc5,0x66,0x3,0x36,0x26,0x7,0x69,0x2c,0x9c,0x6e,0x60,0x67,0xf6,0x87,0x1d,0x3,0x14,0xc0,0x6,0x70,0x80,0x25,0xd,0x11,0xf0,0xc0,0x4b,0x54,0x7c,0x4,0x76,0x40,0x9e,0x68,0xd0,0x3,0x77,0xe0,0x22,0xda,0x79,0x3f,0xf4,0x63,0x4b,0xa0,0x56,0x3e,0x7,0x8f,0x70,0xce,0x72,0x53,0x1,0x37,0xd1,0xb1,0x85,0x40,0xc3,0xc8,0xc3,0x47,0xae,0x73,0x6a,0x67,0x29,0x9,0x34,0xaa,0xb3,0x9f,0x3b,0x17,0x3e,0xf2,0x5c,0x9a,0x5d,0x6b,0x8a,0x89,0xa7,0x1e,0xed,0x2b,0xfe,0x6,0xbf,0x66,0xd0,0x39,0x4b,0xb9,0x24,0xd0,0x9a,0x6e,0xe2,0xa2,0xc1,0x8,0x8,0x2d,0x81,0xda,0x65,0x1c,0x12,0x5e,0xf9,0x4,0x54,0x40,0x34,0xc0,0x76,0x4d,0x98,0xcc,0xda,0x38,0xbf,0x1,0xae,0x5a,0x2a,0xba,0xb8,0xa1,0xb8,0x4f,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; static const unsigned char selection_oof_png[]={ -0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x4c,0x0,0x4a,0x0,0x4e,0x88,0x29,0x6a,0xb6,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x10,0x15,0x32,0x22,0x9b,0x14,0x96,0x1f,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x0,0xba,0x49,0x44,0x41,0x54,0x38,0x8d,0xed,0xd3,0xb1,0x4e,0xc3,0x40,0x10,0x84,0xe1,0xef,0xc2,0x4a,0x9c,0x90,0xb,0x6a,0x9f,0xe0,0x9,0x2,0xbc,0x58,0xc2,0xcb,0xc0,0x8b,0x85,0xa4,0xa6,0x41,0x4e,0x4d,0x41,0x71,0x91,0xe,0x99,0x2,0xd7,0x76,0xa4,0x34,0x14,0x6c,0xb9,0xda,0xf9,0x47,0x2b,0xcd,0x24,0xdc,0xe0,0x16,0x1d,0xae,0x90,0xcc,0xcf,0x88,0x6f,0x7c,0xe1,0x33,0x26,0xf1,0x23,0xee,0x90,0xcf,0x4,0x54,0x7c,0xe0,0x2d,0x26,0xe7,0xfb,0x87,0xf5,0xd3,0xba,0xf4,0x65,0x13,0x11,0xb3,0x80,0xd6,0xda,0x38,0x1c,0x87,0xd7,0xfd,0x61,0x97,0xf0,0x1e,0x8,0x5c,0x97,0xbe,0x6c,0x6b,0xad,0x6a,0xad,0xb3,0xf6,0x39,0xe7,0x54,0xfa,0xb2,0xdd,0x1f,0x76,0xcf,0x88,0xd5,0xb4,0x4f,0x11,0xb1,0x28,0x86,0x5a,0xab,0x88,0x60,0x7a,0x75,0x35,0x7f,0xbe,0x3c,0xff,0x80,0xbf,0x4,0x18,0x5b,0x6b,0x72,0xce,0x8b,0x82,0x9c,0xb3,0xd6,0x1a,0xbf,0x91,0x16,0x68,0x38,0xd,0xc7,0xe1,0xa5,0xf4,0x65,0xd3,0x75,0xdd,0x59,0x51,0xc6,0x9,0x2d,0xa1,0x77,0x41,0x99,0x92,0xb,0xeb,0xfc,0x3,0xd0,0xc5,0x44,0x36,0x1d,0x79,0x84,0xde,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x15,0x0,0x15,0x0,0x17,0xc8,0x7d,0x47,0xd1,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x6,0x14,0x14,0x32,0x15,0xe4,0x5,0x8a,0x4,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0xa5,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0xd3,0x41,0x6a,0x2,0x51,0x10,0x4,0xd0,0xf7,0xe7,0xff,0xc1,0x30,0x4,0xe2,0x5a,0x18,0x4f,0x10,0x2,0x9e,0x29,0xe7,0xca,0x99,0x4,0xc9,0xda,0xcd,0x5c,0x20,0x8b,0x20,0x8a,0xfe,0x8c,0x9b,0x76,0xeb,0x8,0xb3,0xc9,0xc2,0x82,0xde,0x34,0x55,0xd5,0x34,0x54,0x25,0x74,0x58,0xe2,0x15,0x19,0xc9,0x7d,0x8c,0xa8,0xf8,0xc5,0x4f,0x9,0xf1,0x7,0x7a,0xbc,0x3c,0x68,0x70,0xc4,0x80,0x5d,0x89,0xcb,0x6b,0xef,0xcd,0x57,0xdd,0xd6,0x1e,0xed,0x84,0xc1,0x39,0x6f,0xf2,0xe0,0xfb,0xef,0x13,0xfb,0x82,0x82,0x45,0x88,0xf,0x31,0xf7,0xd0,0xd5,0x6d,0xed,0x73,0x9b,0x16,0x28,0x4d,0x2c,0x53,0x5c,0x9e,0x12,0xb,0x4e,0x7b,0x7b,0xb5,0x31,0x13,0x4f,0x83,0xff,0x64,0x30,0xe2,0x1c,0xbd,0x98,0x42,0x17,0xdc,0x51,0xa4,0xf0,0x82,0x53,0xde,0xe4,0x21,0xd2,0xf8,0xf6,0x50,0x94,0x39,0xe1,0x92,0xb0,0x9a,0x53,0xa6,0x34,0xb7,0xce,0x57,0x8f,0xdf,0x31,0x5b,0x17,0xde,0x59,0x7e,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; @@ -379,6 +379,16 @@ static const unsigned char tab_current_png[]={ }; +static const unsigned char tab_menu_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x6,0xd,0x3,0x2c,0x7,0xf7,0x85,0x69,0x73,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0x54,0x49,0x44,0x41,0x54,0x38,0xcb,0xed,0x92,0xb1,0xd,0xc0,0x20,0x10,0x3,0x8f,0xec,0x63,0x65,0xff,0x2d,0x40,0x1e,0xe8,0xd3,0x50,0x24,0xd1,0x83,0x48,0x97,0x2,0xb7,0xb6,0x4f,0xd6,0xeb,0x61,0xeb,0x67,0xb2,0x5d,0xbe,0x66,0x4a,0x12,0x88,0x19,0x40,0xd2,0xa3,0x73,0x24,0x99,0x6,0x64,0x90,0xe8,0x1e,0xd3,0x5,0x7d,0x45,0x3,0x74,0xf3,0x3,0xb0,0xa4,0x73,0x9,0xf0,0x82,0x30,0x2a,0xaf,0x1c,0xb5,0xda,0xae,0xfb,0xbd,0xe6,0xba,0x0,0x22,0x30,0x1e,0x2c,0xd7,0x21,0xa8,0x0,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + +static const unsigned char tab_menu_hl_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x10,0x8,0x6,0x0,0x0,0x0,0x1f,0xf3,0xff,0x61,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xdf,0x6,0xd,0x3,0x2c,0x15,0x4,0x3c,0x18,0x3b,0x0,0x0,0x0,0x1d,0x69,0x54,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x0,0x0,0x0,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x64,0x2e,0x65,0x7,0x0,0x0,0x0,0x58,0x49,0x44,0x41,0x54,0x38,0xcb,0x63,0x60,0x18,0x5,0x83,0xc,0xbc,0x7c,0xf9,0x92,0x91,0x54,0x35,0x8c,0x58,0x14,0xfc,0xc7,0x67,0x80,0xb8,0xb8,0x38,0x8a,0x1e,0x26,0x2c,0x6a,0x2e,0x32,0x30,0x30,0x60,0x33,0xe4,0x3f,0x54,0x8e,0x1,0xaf,0xb,0xa0,0xae,0xb8,0xc8,0xc0,0xc0,0xa0,0x8b,0x24,0xff,0x9f,0x81,0x81,0xe1,0xb2,0xb8,0xb8,0xb8,0x3e,0x51,0x6,0xa0,0x19,0xc2,0x80,0x4b,0x33,0x31,0x81,0x7a,0xe1,0xe5,0xcb,0x97,0x17,0x46,0x93,0x17,0x7e,0x0,0x0,0xa,0x9a,0x1f,0x34,0xff,0x99,0xf7,0x75,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + static const unsigned char toggle_off_png[]={ 0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x40,0x0,0x0,0x0,0x20,0x8,0x6,0x0,0x0,0x0,0xa2,0x9d,0x7e,0x84,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x26,0x0,0x26,0x0,0x26,0x59,0xf,0xde,0x74,0x0,0x0,0x0,0x9,0x70,0x48,0x59,0x73,0x0,0x0,0xb,0x13,0x0,0x0,0xb,0x13,0x1,0x0,0x9a,0x9c,0x18,0x0,0x0,0x0,0x7,0x74,0x49,0x4d,0x45,0x7,0xde,0x9,0x14,0x17,0x2,0x16,0xe9,0x0,0x17,0x60,0x0,0x0,0x0,0x19,0x74,0x45,0x58,0x74,0x43,0x6f,0x6d,0x6d,0x65,0x6e,0x74,0x0,0x43,0x72,0x65,0x61,0x74,0x65,0x64,0x20,0x77,0x69,0x74,0x68,0x20,0x47,0x49,0x4d,0x50,0x57,0x81,0xe,0x17,0x0,0x0,0x2,0x45,0x49,0x44,0x41,0x54,0x68,0x81,0xed,0x99,0x5f,0x4f,0xd3,0x50,0x18,0x87,0x9f,0xb3,0x96,0xb5,0xcc,0x3a,0xa6,0xac,0x6d,0xa,0x91,0x84,0x5b,0x8d,0x7e,0x21,0x60,0x2c,0x5c,0x1a,0x63,0xe2,0x27,0x31,0x31,0xc6,0x4b,0x32,0xa7,0x7e,0x20,0x84,0x6b,0x6f,0xc,0x90,0x6d,0x32,0xca,0x6c,0xb0,0x24,0x75,0xc7,0x8b,0xba,0xb9,0x35,0xdd,0x84,0xec,0xe0,0x26,0xed,0x73,0xd7,0xf7,0xed,0xce,0x7b,0x7e,0xbf,0xbe,0x67,0x7f,0xde,0x41,0x4e,0x4e,0xa6,0x11,0x89,0xeb,0x12,0x50,0x1,0x2c,0x40,0x4b,0xc9,0xff,0xaf,0x48,0xe0,0x27,0x10,0x0,0x3e,0x70,0x39,0x48,0xe8,0x89,0x1b,0x2b,0xc0,0x33,0xe0,0x11,0x60,0x72,0xb7,0xc,0x8,0x81,0xaf,0xc0,0x67,0xa6,0x18,0x60,0x1,0x1b,0x4f,0x1e,0x3f,0x7d,0x6d,0x57,0xed,0x65,0x40,0x48,0x64,0xfc,0x72,0x95,0x8,0x10,0x8,0x74,0x5d,0x67,0x69,0x49,0x47,0xd3,0x92,0xdb,0x50,0x4b,0x14,0x45,0xf2,0xf8,0xe4,0xf8,0xc7,0xe1,0xd1,0xc1,0x2b,0xe0,0xcb,0x68,0x2e,0x59,0x59,0x7,0xc,0xbb,0x6a,0x97,0xce,0xba,0x67,0x4,0x41,0x80,0xec,0xf7,0x91,0x8a,0x1d,0x10,0x8,0x44,0xa1,0x80,0x51,0x2c,0x52,0x2a,0xdd,0xa3,0x58,0x2c,0x2a,0x5d,0x3f,0x89,0x69,0x9a,0x62,0x7d,0x6d,0xbd,0x74,0x78,0x74,0x60,0x90,0xd0,0x9c,0x66,0xbd,0x0,0x8,0x82,0xef,0x54,0x2a,0xf,0x70,0x6c,0x7,0xa1,0xf8,0x24,0x48,0x24,0xed,0x4e,0x1b,0xdf,0x3f,0xc7,0x30,0x4c,0xa5,0x6b,0xa7,0x11,0x86,0x21,0x96,0x65,0x41,0xca,0x91,0x4e,0xed,0x3d,0x29,0x25,0xb2,0x2f,0x71,0x1d,0x97,0x30,0xc,0x39,0x6d,0x9d,0x2a,0xdd,0x90,0xe7,0x7a,0xb8,0x8e,0xcb,0x79,0xb7,0xab,0xbc,0xbb,0x6e,0x4a,0x61,0x52,0x62,0x70,0xf6,0x55,0x8b,0x87,0xdf,0x6b,0x4a,0xe6,0x2e,0x1e,0xa6,0x18,0x90,0x15,0x32,0x6f,0xc0,0xed,0x7e,0xfe,0xcc,0x80,0x65,0x59,0xd4,0xf7,0x6a,0x63,0xb1,0xc6,0x7e,0x93,0x20,0x8,0x78,0xf1,0xf2,0xf9,0x58,0xfc,0xed,0x9b,0x77,0xa9,0xb1,0xeb,0xb0,0xb0,0x6,0xc,0xc4,0x7f,0x78,0xff,0x9,0x80,0x9d,0xdd,0x2d,0xea,0x7b,0xb5,0xa1,0xb0,0x34,0x81,0xd7,0x15,0x3d,0xca,0xc2,0x1a,0x0,0xd0,0x6c,0x7c,0xa4,0xd7,0xeb,0x1,0xb1,0x11,0x3b,0xbb,0x5b,0xc3,0xdc,0xe8,0x13,0x1f,0x8,0x4f,0x8b,0xfd,0x8d,0x85,0x36,0x60,0x1a,0xaa,0x3a,0x60,0xa1,0xdf,0x4,0x6b,0xf5,0x6d,0xca,0xe5,0x32,0xe5,0x72,0x79,0xec,0xe9,0xab,0x24,0x69,0x80,0x9,0xac,0xdc,0x4a,0xa5,0x1b,0xd2,0xd8,0x6f,0x2,0xb1,0x9,0xb5,0xfa,0xf6,0x58,0x6c,0x6,0x56,0x88,0x35,0xe,0x49,0x1e,0x81,0x10,0xb8,0x98,0xb5,0x8a,0xa,0x82,0x20,0x98,0xd8,0xd2,0x33,0xb4,0xff,0x5,0xb1,0xc6,0x21,0xb,0x7d,0x4,0xfe,0x5,0xb9,0x1,0xf3,0xde,0xc0,0xbc,0x99,0x68,0x80,0x88,0xa7,0x16,0x78,0xae,0xa7,0xbc,0xa8,0xe7,0x7a,0xc3,0xa1,0xc8,0xbc,0x49,0xfd,0x1e,0x20,0x84,0x40,0x14,0x4,0xad,0x76,0xb,0xc7,0x76,0xd8,0xdc,0xd8,0x54,0x5a,0x54,0x22,0x69,0xb5,0x5b,0x88,0x82,0x98,0xbb,0x9,0x69,0x6,0x48,0x0,0xcb,0xba,0x8f,0xef,0xfb,0xb7,0xf2,0x9b,0xfd,0xcf,0x44,0xc8,0x40,0xd3,0x34,0xa5,0x6b,0xa7,0x61,0x9a,0x26,0x51,0x14,0x41,0xca,0x70,0x2f,0x69,0x40,0x4,0x5c,0x75,0xbe,0x75,0x2e,0xed,0xaa,0xbd,0xbc,0xfa,0x70,0xf5,0x4e,0xcd,0x4,0x81,0x2b,0x62,0x8d,0xa3,0x5b,0x19,0x63,0x8d,0x6c,0x4c,0x85,0x4f,0x6,0x89,0xcc,0xff,0x2f,0x90,0x93,0x93,0x93,0x6d,0x7e,0x1,0x6b,0xe,0xc1,0xdb,0xd6,0xe0,0xc4,0xba,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp index a598c69089..2d93113b40 100644 --- a/scene/resources/font.cpp +++ b/scene/resources/font.cpp @@ -510,6 +510,7 @@ float Font::draw_char(RID p_canvas_item, const Point2& p_pos, const CharType& p_ void Font::_bind_methods() { + ObjectTypeDB::bind_method(_MD("create_from_fnt","path"),&Font::create_from_fnt); ObjectTypeDB::bind_method(_MD("set_height","px"),&Font::set_height); ObjectTypeDB::bind_method(_MD("get_height"),&Font::get_height); 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/mesh.cpp b/scene/resources/mesh.cpp index 039a4788d5..8cb0904415 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -99,7 +99,7 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) { if (sl==-1) return false; int idx=sname.substr(8,sl-8).to_int()-1; - String what = sname.get_slice("/",1); + String what = sname.get_slicec('/',1); if (what=="material") surface_set_material(idx,p_value); else if (what=="name") @@ -117,8 +117,8 @@ bool Mesh::_set(const StringName& p_name, const Variant& p_value) { return false; - int idx=sname.get_slice("/",1).to_int(); - String what=sname.get_slice("/",2); + int idx=sname.get_slicec('/',1).to_int(); + String what=sname.get_slicec('/',2); if (idx==surfaces.size()) { @@ -180,7 +180,7 @@ bool Mesh::_get(const StringName& p_name,Variant &r_ret) const { if (sl==-1) return false; int idx=sname.substr(8,sl-8).to_int()-1; - String what = sname.get_slice("/",1); + String what = sname.get_slicec('/',1); if (what=="material") r_ret=surface_get_material(idx); else if (what=="name") @@ -195,7 +195,7 @@ bool Mesh::_get(const StringName& p_name,Variant &r_ret) const { return false; - int idx=sname.get_slice("/",1).to_int(); + int idx=sname.get_slicec('/',1).to_int(); ERR_FAIL_INDEX_V(idx,surfaces.size(),false); Dictionary d; diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp index ffa29572ff..5ebab9be76 100644 --- a/scene/resources/mesh_library.cpp +++ b/scene/resources/mesh_library.cpp @@ -35,8 +35,8 @@ bool MeshLibrary::_set(const StringName& p_name, const Variant& p_value) { String name=p_name; if (name.begins_with("item/")) { - int idx = name.get_slice("/",1).to_int(); - String what = name.get_slice("/",2); + int idx = name.get_slicec('/',1).to_int(); + String what = name.get_slicec('/',2); if (!item_map.has(idx)) create_item(idx); @@ -60,9 +60,9 @@ bool MeshLibrary::_set(const StringName& p_name, const Variant& p_value) { bool MeshLibrary::_get(const StringName& p_name,Variant &r_ret) const { String name=p_name; - int idx = name.get_slice("/",1).to_int(); + int idx = name.get_slicec('/',1).to_int(); ERR_FAIL_COND_V(!item_map.has(idx),false); - String what = name.get_slice("/",2); + String what = name.get_slicec('/',2); if(what=="name") r_ret= get_item_name(idx); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index a1cb1205e5..a9dc0e8bfb 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -32,13 +32,30 @@ #include "scene/3d/spatial.h" #include "scene/gui/control.h" #include "scene/2d/node_2d.h" +#include "scene/main/instance_placeholder.h" -bool PackedScene::can_instance() const { +#define PACK_VERSION 2 + +bool SceneState::can_instance() const { return nodes.size()>0; } -Node *PackedScene::instance(bool p_gen_edit_state) const { + +Node *SceneState::instance(bool p_gen_edit_state) const { + + // nodes where instancing failed (because something is missing) + List<Node*> stray_instances; + +#define NODE_FROM_ID(p_name,p_id)\ + Node *p_name;\ + if (p_id&FLAG_ID_IS_PATH) {\ + NodePath np=node_paths[p_id&FLAG_MASK];\ + p_name=ret_nodes[0]->_get_node(np);\ + } else {\ + ERR_FAIL_INDEX_V(p_id&FLAG_MASK,nc,NULL);\ + p_name=ret_nodes[p_id&FLAG_MASK];\ + } int nc = nodes.size(); ERR_FAIL_COND_V(nc==0,NULL); @@ -53,35 +70,86 @@ Node *PackedScene::instance(bool p_gen_edit_state) const { if (prop_count) props=&variants[0]; - Vector<Variant> properties; + //Vector<Variant> properties; const NodeData *nd = &nodes[0]; Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc ); + bool gen_node_path_cache=p_gen_edit_state && node_path_cache.empty(); for(int i=0;i<nc;i++) { const NodeData &n=nd[i]; - if (!ObjectTypeDB::is_type_enabled(snames[n.type])) { - ret_nodes[i]=NULL; - continue; + Node *parent=NULL; + + if (i>0) { + + NODE_FROM_ID(nparent,n.parent); +#ifdef DEBUG_ENABLED + if (!nparent && n.parent&FLAG_ID_IS_PATH) { + + WARN_PRINT(String("Parent path '"+String(node_paths[n.parent&FLAG_MASK])+"' for node '"+String(snames[n.name])+"' has vanished when instancing: '"+get_path()+"'.").ascii().get_data()); + + } +#endif + parent=nparent; } Node *node=NULL; - if (n.instance>=0) { - //instance existing - Ref<PackedScene> sdata = props[ n.instance ]; + if (i==0 && base_scene_idx>=0) { + //scene inheritance on root node + print_line("scene inherit"); + Ref<PackedScene> sdata = props[ base_scene_idx ]; ERR_FAIL_COND_V( !sdata.is_valid(), NULL); - node = sdata->instance(); + node = sdata->instance(p_gen_edit_state); ERR_FAIL_COND_V(!node,NULL); - if (p_gen_edit_state) - node->generate_instance_state(); + if (p_gen_edit_state) { + node->set_scene_inherited_state(sdata->get_state()); + } - } else { - //create anew + } else if (n.instance>=0) { + //instance a scene into this node + print_line("instance"); + if (n.instance&FLAG_INSTANCE_IS_PLACEHOLDER) { + + String path = props[n.instance&FLAG_MASK]; + if (disable_placeholders) { + + Ref<PackedScene> sdata = ResourceLoader::load(path,"PackedScene"); + ERR_FAIL_COND_V( !sdata.is_valid(), NULL); + node = sdata->instance(p_gen_edit_state); + ERR_FAIL_COND_V(!node,NULL); + } else { + InstancePlaceholder *ip = memnew( InstancePlaceholder ); + ip->set_path(path); + node=ip; + } + node->set_scene_instance_load_placeholder(true); + } else { + Ref<PackedScene> sdata = props[ n.instance&FLAG_MASK ]; + ERR_FAIL_COND_V( !sdata.is_valid(), NULL); + node = sdata->instance(p_gen_edit_state); + ERR_FAIL_COND_V(!node,NULL); + + } + + } else if (n.type==TYPE_INSTANCED) { + //print_line("instanced"); + //get the node from somewhere, it likely already exists from another instance + if (parent) { + node=parent->_get_child_by_name(snames[n.name]); +#ifdef DEBUG_ENABLED + if (!node) { + WARN_PRINT(String("Node '"+String(ret_nodes[0]->get_path_to(parent))+"/"+String(snames[n.name])+"' was modified from inside a instance, but it has vanished.").ascii().get_data()); + } +#endif + } + } else if (ObjectTypeDB::is_type_enabled(snames[n.type])) { + print_line("created"); + //node belongs to this scene and must be created Object * obj = ObjectTypeDB::instance(snames[ n.type ]); if (!obj || !obj->cast_to<Node>()) { if (obj) { @@ -109,49 +177,68 @@ Node *PackedScene::instance(bool p_gen_edit_state) const { } - //properties - int nprop_count=n.properties.size(); - if (nprop_count) { + if (node) { + // may not have found the node (part of instanced scene and removed) + // if found all is good, otherwise ignore + + //properties + int nprop_count=n.properties.size(); + if (nprop_count) { - const NodeData::Property* nprops=&n.properties[0]; + const NodeData::Property* nprops=&n.properties[0]; - for(int j=0;j<nprop_count;j++) { + for(int j=0;j<nprop_count;j++) { - bool valid; - ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL ); - ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL ); + bool valid; + ERR_FAIL_INDEX_V( nprops[j].name, sname_count, NULL ); + ERR_FAIL_INDEX_V( nprops[j].value, prop_count, NULL ); - node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid); + node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid); + } } - } - //name + //name - //groups - for(int j=0;j<n.groups.size();j++) { + //groups + for(int j=0;j<n.groups.size();j++) { - ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL ); - node->add_to_group( snames[ n.groups[j] ], true ); - } + ERR_FAIL_INDEX_V( n.groups[j], sname_count, NULL ); + node->add_to_group( snames[ n.groups[j] ], true ); + } + if (n.instance>=0 || n.type!=TYPE_INSTANCED) { + //if node was not part of instance, must set it's name, parenthood and ownership + if (i>0) { + if (parent) { + parent->_add_child_nocheck(node,snames[n.name]); + } else { + //it may be possible that an instanced scene has changed + //and the node has nowhere to go anymore + stray_instances.push_back(node); //can't be added, go to stray list + } + } else { + node->_set_name_nocheck( snames[ n.name ] ); + } - ret_nodes[i]=node; + } - if (i>0) { - ERR_FAIL_INDEX_V(n.parent,i,NULL); - ERR_FAIL_COND_V(!ret_nodes[n.parent],NULL); - ret_nodes[n.parent]->_add_child_nocheck(node,snames[n.name]); - } else { - node->_set_name_nocheck( snames[ n.name ] ); - } + if (n.owner>=0) { + NODE_FROM_ID(owner,n.owner); + if (owner) + node->_set_owner_nocheck(owner); + } - if (n.owner>=0) { - ERR_FAIL_INDEX_V(n.owner,i,NULL); - node->_set_owner_nocheck(ret_nodes[n.owner]); } + + ret_nodes[i]=node; + + if (node && gen_node_path_cache && ret_nodes[0]) { + NodePath n = ret_nodes[0]->get_path_to(node); + node_path_cache[n]=i; + } } @@ -163,8 +250,14 @@ Node *PackedScene::instance(bool p_gen_edit_state) const { for(int i=0;i<cc;i++) { const ConnectionData &c=cdata[i]; - ERR_FAIL_INDEX_V( c.from, nc, NULL ); - ERR_FAIL_INDEX_V( c.to, nc, NULL ); + //ERR_FAIL_INDEX_V( c.from, nc, NULL ); + //ERR_FAIL_INDEX_V( c.to, nc, NULL ); + + NODE_FROM_ID(cfrom,c.from); + NODE_FROM_ID(cto,c.to); + + if (!cfrom || !cto) + continue; Vector<Variant> binds; if (c.binds.size()) { @@ -173,17 +266,25 @@ Node *PackedScene::instance(bool p_gen_edit_state) const { binds[j]=props[ c.binds[j] ]; } - if (!ret_nodes[c.from] || !ret_nodes[c.to]) - continue; - ret_nodes[c.from]->connect( snames[ c.signal], ret_nodes[ c.to ], snames[ c.method], binds,CONNECT_PERSIST|c.flags ); + + cfrom->connect( snames[ c.signal], cto, snames[ c.method], binds,CONNECT_PERSIST|c.flags ); } - Node *s = ret_nodes[0]; + //Node *s = ret_nodes[0]; - if (get_path()!="" && get_path().find("::")==-1) - s->set_filename(get_path()); + //remove nodes that could not be added, likely as a result that + while(stray_instances.size()) { + memdelete(stray_instances.front()->get()); + stray_instances.pop_front();; + } + + for(int i=0;i<editable_instances.size();i++) { + Node *ei = ret_nodes[0]->_get_node(editable_instances[i]); + if (ei) { + ret_nodes[0]->set_editable_instance(ei,true); + } + } - s->notification(Node::NOTIFICATION_INSTANCED); return ret_nodes[0]; } @@ -209,44 +310,157 @@ static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,Variant return idx; } -Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) { +Error SceneState::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map) { + - if (p_node!=p_owner && (p_node->get_owner()!=p_owner)) - return OK; //nothing to do with this node, may either belong to another scene or be onowned + // this function handles all the work related to properly packing scenes, be it + // instanced or inherited. + // given the complexity of this process, an attempt will be made to properly + // document it. if you fail to understand something, please ask! + + //discard nodes that do not belong to be processed + if (p_node!=p_owner && p_node->get_owner()!=p_owner && !p_owner->is_editable_instance(p_node->get_owner())) + return OK; + + // save the child instanced scenes that are chosen as editable, so they can be restored + // upon load back + if (p_node!=p_owner && p_node->get_filename()!=String() && p_owner->is_editable_instance(p_node)) + editable_instances.push_back(p_owner->get_path_to(p_node)); NodeData nd; nd.name=_nm_get_string(p_node->get_name(),name_map); - nd.type=_nm_get_string(p_node->get_type(),name_map); - nd.parent=p_parent_idx; + nd.instance=-1; //not instanced by default + + // if this node is part of an instanced scene or sub-instanced scene + // we need to get the corresponding instance states. + // with the instance states, we can query for identical properties/groups + // and only save what has changed + + List<PackState> pack_state_stack; + + bool instanced_by_owner=true; + + { + Node *n=p_node; + + while(n) { + + if (n==p_owner) { + + Ref<SceneState> state = n->get_scene_inherited_state(); + if (state.is_valid()) { + int node = state->find_node_by_path(n->get_path_to(p_node)); + if (node>=0) { + //this one has state for this node, save + PackState ps; + ps.node=node; + ps.state=state; + pack_state_stack.push_front(ps); + instanced_by_owner=false; + } + } + + if (p_node->get_filename()!=String() && p_node->get_owner()==p_owner && instanced_by_owner) { + + if (p_node->get_scene_instance_load_placeholder()) { + //it's a placeholder, use the placeholder path + nd.instance=_vm_get_variant(p_node->get_filename(),variant_map); + nd.instance|=FLAG_INSTANCE_IS_PLACEHOLDER; + } else { + //must instance ourselves + Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename()); + if (!instance.is_valid()) { + return ERR_CANT_OPEN; + } + nd.instance=_vm_get_variant(instance,variant_map); + } + } + n=NULL; + } else { + if (n->get_filename()!=String()) { + //is an instance + Ref<SceneState> state = n->get_scene_instance_state(); + if (state.is_valid()) { + int node = state->find_node_by_path(n->get_path_to(p_node)); + if (node>=0) { + //this one has state for this node, save + PackState ps; + ps.node=node; + ps.state=state; + pack_state_stack.push_back(ps); + } + } + + } + n=n->get_owner(); + } + } + } + +#if 0 + + Ref<SceneState> base_scene = p_node->get_scene_inherited_state(); //for inheritance + Ref<SceneState> instance_state; + int instance_state_node=-1; + + if (base_scene.is_valid() && (p_node==p_owner || p_node->get_owner()==p_owner)) { + //scene inheritance in use, see if this node is actually inherited + NodePath path = p_owner->get_path_to(p_node); + instance_state_node = base_scene->find_node_by_path(path); + if (instance_state_node>=0) { + instance_state=base_scene; + } + } - Dictionary instance_state; - Set<StringName> instance_groups; + // check that this is a directly instanced scene from the scene being packed, if so + // this information must be saved. Of course, if using scene instancing and this node + // does belong to base scene, ignore. + if (instance_state.is_null() && p_node!=p_owner && p_node->get_owner()==p_owner && p_node->get_filename()!="") { - if (p_node!=p_owner && p_node->get_filename()!="") { - //instanced + //instanced, only direct sub-scnes are supported of course Ref<PackedScene> instance = ResourceLoader::load(p_node->get_filename()); if (!instance.is_valid()) { return ERR_CANT_OPEN; } nd.instance=_vm_get_variant(instance,variant_map); - instance_state = p_node->get_instance_state(); - Vector<StringName> ig = p_node->get_instance_groups(); - for(int i=0;i<ig.size();i++) - instance_groups.insert(ig[i]); + } else { nd.instance=-1; } + // finally, if this does not belong to scene inheritance, check + // if it belongs to scene instancing + + if (instance_state.is_null() && p_node!=p_owner) { + //if not affected by scene inheritance, this may be + if (p_node->get_owner()==p_owner && p_node->get_filename()!=String()) { + instance_state=p_node->get_scene_instance_state(); + if (instance_state.is_valid()) { + instance_state_node=instance_state->find_node_by_path(p_node->get_path_to(p_node)); + } - //instance state makes sure that only changes to instance are saved + } else if (p_node->get_owner()!=p_owner && p_owner->is_editable_instance(p_node->get_owner())) { + instance_state=p_node->get_owner()->get_scene_instance_state(); + if (instance_state.is_valid()) { + instance_state_node=instance_state->find_node_by_path(p_node->get_owner()->get_path_to(p_node)); + } + } + } +#endif + int subscene_prop_search_from=0; + + // all setup, we then proceed to check all properties for the node + // and save the ones that are worth saving List<PropertyInfo> plist; p_node->get_property_list(&plist); + + for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { @@ -257,31 +471,63 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map< String name = E->get().name; Variant value = p_node->get( E->get().name ); - if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero()) { - continue; - } + bool isdefault = ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one()); + +// if (nd.instance<0 && ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO) && value.is_zero()) || ((E->get().usage & PROPERTY_USAGE_STORE_IF_NONONE) && value.is_one())) { +// continue; +// } - if (nd.instance>=0) { - //only save changed properties in instance - /* - // this was commented because it would not save properties created from within script - // done with _get_property_list, that are not in the original node. - // if some property is not saved, check again - if (!instance_state.has(name)) { - print_line("skip not in instance"); + + //print_line("PASSED!"); + //print_line("at: "+String(p_node->get_name())+"::"+name+": - nz: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO)+" no: "+itos(E->get().usage&PROPERTY_USAGE_STORE_IF_NONONE)); + //print_line("value: "+String(value)+" is zero: "+itos(value.is_zero())+" is one" +itos(value.is_one())); + + if (pack_state_stack.size()) { + // we are on part of an instanced subscene + // or part of instanced scene. + // only save what has been changed + // only save changed properties in instance + + if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE || E->get().name=="__meta__") { + //property has requested that no instance state is saved, sorry + //also, meta won't be overriden or saved continue; - }*/ + } + + bool exists=false; + Variant original; + + for (List<PackState>::Element *F=pack_state_stack.back();F;F=F->prev()) { + //check all levels of pack to see if the property exists somewhere + const PackState &ps=F->get(); - if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE) { + original = ps.state->get_property_value(ps.node,E->get().name,exists); + if (exists) { + break; + } + } + + + if (exists && bool(Variant::evaluate(Variant::OP_EQUAL,value,original))) { + //exists and did not change continue; } - if (instance_state[name]==value) { + if (!exists && isdefault) { + //does not exist in original node, but it's the default value + //so safe to skip too. continue; } + + } else { + + if (isdefault) { + //it's the default value, no point in saving it + continue; + } } NodeData::Property prop; @@ -292,6 +538,9 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map< } + // save the groups this node is into + // discard groups that come from the original scene + List<Node::GroupInfo> groups; p_node->get_groups(&groups); for(List<Node::GroupInfo>::Element *E=groups.front();E;E=E->next()) { @@ -299,27 +548,123 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map< if (!gi.persistent) continue; - if (nd.instance>=0 && instance_groups.has(gi.name)) - continue; //group was instanced, don't add here +// if (instance_state_node>=0 && instance_state->is_node_in_group(instance_state_node,gi.name)) +// continue; //group was instanced, don't add here + + bool skip=false; + for (List<PackState>::Element *F=pack_state_stack.front();F;F=F->next()) { + //check all levels of pack to see if the group was added somewhere + const PackState &ps=F->get(); + if (ps.state->is_node_in_group(ps.node,gi.name)) { + skip=true; + break; + } + } + + if (skip) + continue; nd.groups.push_back(_nm_get_string(gi.name,name_map)); } - if (node_map.has(p_node->get_owner())) - nd.owner=node_map[p_node->get_owner()]; - else + + // save the right owner + // for the saved scene root this is -1 + // for nodes of the saved scene this is 0 + // for nodes of instanced scenes this is >0 + + if (p_node==p_owner) { + //saved scene root + nd.owner=-1; + } else if (p_node->get_owner()==p_owner) { + //part of saved scene + nd.owner=0; + } else { + nd.owner=-1; +#if 0 + // this is pointless, if this was instanced by something else, + // the owner will already be set. + + if (node_map.has(p_node->get_owner())) { + //maybe an existing saved node + nd.owner=node_map[p_node->get_owner()]; + } else { + //not saved, use nodepath map + int sidx; + if (nodepath_map.has(p_node->get_owner())) { + sidx=nodepath_map[p_node->get_owner()]; + } else { + sidx=nodepath_map.size(); + nodepath_map[p_node->get_owner()]=sidx; + } + + nd.owner=FLAG_ID_IS_PATH|sidx; + + } +#endif + + + } + + // Save the right type. If this node was created by an instance + // then flag that the node should not be created but reused + if (pack_state_stack.empty()) { + //this node is not part of an instancing process, so save the type + nd.type=_nm_get_string(p_node->get_type(),name_map); + } else { + // this node is part of an instanced process, so do not save the type. + // instead, save that it was instanced + nd.type=TYPE_INSTANCED; + } + + + // determine whether to save this node or not + // if this node is part of an instanced sub-scene, we can skip storing it if basically + // no properties changed and no groups were added to it. + // below condition is true for all nodes of the scene being saved, and ones in subscenes + // that hold changes + + bool save_node = nd.properties.size() || nd.groups.size(); // some local properties or groups exist + save_node = save_node || p_node==p_owner; // owner is always saved + save_node = save_node || (p_node->get_owner()==p_owner && instanced_by_owner); //part of scene and not instanced + int idx = nodes.size(); - node_map[p_node]=idx; - nodes.push_back(nd); + int parent_node=NO_PARENT_SAVED; + + if (save_node) { + //don't save the node if nothing and subscene + + node_map[p_node]=idx; + + //ok validate parent node + if (p_parent_idx==NO_PARENT_SAVED) { + + int sidx; + if (nodepath_map.has(p_node->get_parent())) { + sidx=nodepath_map[p_node->get_parent()]; + } else { + sidx=nodepath_map.size(); + nodepath_map[p_node->get_parent()]=sidx; + } + + nd.parent=FLAG_ID_IS_PATH|sidx; + } else { + nd.parent=p_parent_idx; + } + + parent_node=idx; + nodes.push_back(nd); + + } for(int i=0;i<p_node->get_child_count();i++) { Node *c=p_node->get_child(i); - Error err = _parse_node(p_owner,c,idx,name_map,variant_map,node_map); + Error err = _parse_node(p_owner,c,parent_node,name_map,variant_map,node_map,nodepath_map); if (err) return err; } @@ -328,53 +673,135 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map< } -Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map) { - - if (p_node!=p_owner && (p_node->get_owner()!=p_owner)) - return OK; //nothing to do with this node, may either belong to another scene or be onowned - - List<MethodInfo> signals; - p_node->get_signal_list(&signals); +Error SceneState::_parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map) { - ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG); - NodeData &nd = nodes[node_map[p_node]]; - Set<Connection> instance_connections; + if (p_node!=p_owner && p_node->get_owner() && p_node->get_owner()!=p_owner && !p_owner->is_editable_instance(p_node->get_owner())) + return OK; - if (nd.instance>=0) { - Vector<Connection> iconns = p_node->get_instance_connections(); - for(int i=0;i<iconns.size();i++) { + List<MethodInfo> _signals; + p_node->get_signal_list(&_signals); - instance_connections.insert(iconns[i]); - } - } + //ERR_FAIL_COND_V( !node_map.has(p_node), ERR_BUG); + //NodeData &nd = nodes[node_map[p_node]]; - for(List<MethodInfo>::Element *E=signals.front();E;E=E->next()) { + for(List<MethodInfo>::Element *E=_signals.front();E;E=E->next()) { List<Node::Connection> conns; p_node->get_signal_connection_list(E->get().name,&conns); for(List<Node::Connection>::Element *F=conns.front();F;F=F->next()) { const Node::Connection &c = F->get(); - if (!(c.flags&CONNECT_PERSIST)) + + if (!(c.flags&CONNECT_PERSIST)) //only persistent connections get saved continue; - if (nd.instance>=0 && instance_connections.has(c)) - continue; //came from instance, don't save! + // only connections that originate or end into main saved scene are saved + // everything else is discarded Node *n=c.target->cast_to<Node>(); - if (!n) + if (!n) { continue; + } + + //source node is outside saved scene? + bool src_is_out = p_node!=p_owner && (p_node->get_filename()!=String() || p_node->get_owner()!=p_owner); + //target node is outside saved scene? + bool dst_is_out = n!=p_owner && (n->get_filename()!=String() || n->get_owner()!=p_owner); - if (!node_map.has(n)) { - WARN_PRINT("Connection to node outside scene??") + //if both are out, ignore connection + if (src_is_out && dst_is_out) { continue; } + + { + Node *nl=p_node; + + bool exists=false; + + while(nl) { + + if (nl==p_owner) { + + Ref<SceneState> state = nl->get_scene_inherited_state(); + if (state.is_valid()) { + int from_node = state->find_node_by_path(nl->get_path_to(p_node)); + int to_node = state->find_node_by_path(nl->get_path_to(n)); + + if (from_node>=0 && to_node>=0) { + //this one has state for this node, save + if (state->is_connection(from_node,c.signal,to_node,c.method)) { + exists=true; + break; + } + } + } + + nl=NULL; + } else { + if (nl->get_filename()!=String()) { + //is an instance + Ref<SceneState> state = nl->get_scene_instance_state(); + if (state.is_valid()) { + int from_node = state->find_node_by_path(nl->get_path_to(p_node)); + int to_node = state->find_node_by_path(nl->get_path_to(n)); + + if (from_node>=0 && to_node>=0) { + //this one has state for this node, save + if (state->is_connection(from_node,c.signal,to_node,c.method)) { + exists=true; + break; + } + } + } + + } + nl=nl->get_owner(); + } + } + + if (exists) { + continue; + } + + } + + + int src_id; + + if (node_map.has(p_node)) { + src_id=node_map[p_node]; + } else { + if (nodepath_map.has(p_node)) { + src_id=FLAG_ID_IS_PATH|nodepath_map[p_node]; + } else { + int sidx=nodepath_map.size(); + nodepath_map[p_node]=sidx; + src_id=FLAG_ID_IS_PATH|sidx; + } + } + + + + int target_id; + + if (node_map.has(n)) { + target_id=node_map[n]; + } else { + if (nodepath_map.has(n)) { + target_id=FLAG_ID_IS_PATH|nodepath_map[n]; + } else { + int sidx=nodepath_map.size(); + nodepath_map[n]=sidx; + target_id=FLAG_ID_IS_PATH|sidx; + } + } + ConnectionData cd; - cd.from=node_map[p_node]; - cd.to=node_map[n]; + cd.from=src_id; + cd.to=target_id; cd.method=_nm_get_string(c.method,name_map); cd.signal=_nm_get_string(c.signal,name_map); cd.flags=c.flags; @@ -389,7 +816,7 @@ Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName for(int i=0;i<p_node->get_child_count();i++) { Node *c=p_node->get_child(i); - Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map); + Error err = _parse_connections(p_owner,c,name_map,variant_map,node_map,nodepath_map); if (err) return err; } @@ -398,7 +825,7 @@ Error PackedScene::_parse_connections(Node *p_owner,Node *p_node, Map<StringName } -Error PackedScene::pack(Node *p_scene) { +Error SceneState::pack(Node *p_scene) { ERR_FAIL_NULL_V( p_scene, ERR_INVALID_PARAMETER ); @@ -409,14 +836,27 @@ Error PackedScene::pack(Node *p_scene) { Map<StringName,int> name_map; HashMap<Variant,int,VariantHasher> variant_map; Map<Node*,int> node_map; + Map<Node*,int> nodepath_map; + + //if using scene inheritance, pack the scene it inherits from + if (scene->get_scene_inherited_state().is_valid()) { + String path = scene->get_scene_inherited_state()->get_path(); + Ref<PackedScene> instance = ResourceLoader::load(path); + if (instance.is_valid()) { + + base_scene_idx=_vm_get_variant(instance,variant_map); + } + } + //instanced, only direct sub-scnes are supported of course + - Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map); + Error err = _parse_node(scene,scene,-1,name_map,variant_map,node_map,nodepath_map); if (err) { clear(); ERR_FAIL_V(err); } - err = _parse_connections(scene,scene,name_map,variant_map,node_map); + err = _parse_connections(scene,scene,name_map,variant_map,node_map,nodepath_map); if (err) { clear(); ERR_FAIL_V(err); @@ -437,19 +877,177 @@ Error PackedScene::pack(Node *p_scene) { variants[idx]=*K; } + node_paths.resize(nodepath_map.size()); + for(Map<Node*,int>::Element *E=nodepath_map.front();E;E=E->next()) { + + node_paths[E->get()]=scene->get_path_to(E->key()); + } + + return OK; } -void PackedScene::clear() { +void SceneState::set_path(const String &p_path) { + + path=p_path; +} + +String SceneState::get_path() const{ + + return path; +} + +void SceneState::clear() { names.clear(); variants.clear(); nodes.clear(); connections.clear(); + node_path_cache.clear(); + node_paths.clear(); + editable_instances.clear(); + base_scene_idx=-1; } -void PackedScene::_set_bundled_scene(const Dictionary& d) { +Ref<SceneState> SceneState::_get_base_scene_state() const { + + if (base_scene_idx>=0) { + + Ref<PackedScene> ps = variants[base_scene_idx]; + if (ps.is_valid()) { + return ps->get_state(); + } + } + + return Ref<SceneState>(); +} + +int SceneState::find_node_by_path(const NodePath& p_node) const { + + if (!node_path_cache.has(p_node)) { + if (_get_base_scene_state().is_valid()) { + int idx = _get_base_scene_state()->find_node_by_path(p_node); + if (idx>=0) { + if (!base_scene_node_remap.has(idx)) { + int ridx = nodes.size() + base_scene_node_remap.size(); + base_scene_node_remap[ridx]=idx; + } + + return base_scene_node_remap[idx]; + } + } + return -1; + } + + int nid = node_path_cache[p_node]; + + if (_get_base_scene_state().is_valid() && !base_scene_node_remap.has(nid)) { + //for nodes that _do_ exist in current scene, still try to look for + //the node in the instanced scene, as a property may be missing + //from the local one + int idx = _get_base_scene_state()->find_node_by_path(p_node); + base_scene_node_remap[nid]=idx; + + } + + return nid; +} +Variant SceneState::get_property_value(int p_node, const StringName& p_property, bool &found) const { + + found=false; + + ERR_FAIL_COND_V(p_node<0,Variant()); + + if (p_node<nodes.size()) { + //find in built-in nodes + int pc = nodes[p_node].properties.size(); + const StringName* namep = names.ptr(); + + const NodeData::Property *p=nodes[p_node].properties.ptr(); + for(int i=0;i<pc;i++) { + if (p_property==namep[p[i].name]) { + found=true; + return variants[p[i].value]; + } + } + } + + //property not found, try on instance + + if (base_scene_node_remap.has(p_node)) { + return _get_base_scene_state()->get_property_value(base_scene_node_remap[p_node],p_property,found); + } + + return Variant(); +} + +bool SceneState::is_node_in_group(int p_node,const StringName& p_group) const { + + ERR_FAIL_COND_V(p_node<0,false); + + if (p_node<nodes.size()) { + const StringName* namep = names.ptr(); + for(int i=0;i<nodes[p_node].groups.size();i++) { + if (namep[nodes[p_node].groups[i]]==p_group) + return true; + } + } + + if (base_scene_node_remap.has(p_node)) { + return _get_base_scene_state()->is_node_in_group(base_scene_node_remap[p_node],p_group); + } + + return false; +} + +bool SceneState::disable_placeholders=false; + +void SceneState::set_disable_placeholders(bool p_disable) { + + disable_placeholders=p_disable; +} + +bool SceneState::is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const { + + ERR_FAIL_COND_V(p_node<0,false); + ERR_FAIL_COND_V(p_to_node<0,false); + + if (p_node<nodes.size() && p_to_node<nodes.size()) { + + int signal_idx=-1; + int method_idx=-1; + for(int i=0;i<names.size();i++) { + if (names[i]==p_signal) { + signal_idx=i; + } else if (names[i]==p_to_method) { + method_idx=i; + } + } + + if (signal_idx>=0 && method_idx>=0) { + //signal and method strings are stored.. + + for(int i=0;i<connections.size();i++) { + + if (connections[i].from==p_node && connections[i].to==p_to_node && connections[i].signal==signal_idx && connections[i].method==method_idx) { + + return true; + } + } + } + } + + if (base_scene_node_remap.has(p_node) && base_scene_node_remap.has(p_to_node)) { + return _get_base_scene_state()->is_connection(base_scene_node_remap[p_node],p_signal,base_scene_node_remap[p_to_node],p_to_method); + } + + return false; + +} + + +void SceneState::set_bundled_scene(const Dictionary& d) { ERR_FAIL_COND( !d.has("names")); @@ -460,6 +1058,15 @@ void PackedScene::_set_bundled_scene(const Dictionary& d) { ERR_FAIL_COND( !d.has("conns")); // ERR_FAIL_COND( !d.has("path")); + int version=1; + if (d.has("version")) + version=d["version"]; + + if (version>PACK_VERSION) { + ERR_EXPLAIN("Save format version too new!"); + ERR_FAIL(); + } + DVector<String> snames = d["names"]; if (snames.size()) { @@ -537,11 +1144,34 @@ void PackedScene::_set_bundled_scene(const Dictionary& d) { } + Array np; + if (d.has("node_paths")) { + np=d["node_paths"]; + } + node_paths.resize(np.size()); + for(int i=0;i<np.size();i++) { + node_paths[i]=np[i]; + } + + Array ei; + if (d.has("editable_instances")) { + ei=d["editable_instances"]; + } + + if (d.has("base_scene")) { + base_scene_idx=d["base_scene"]; + } + + editable_instances.resize(ei.size()); + for(int i=0;i<editable_instances.size();i++) { + editable_instances[i]=ei[i]; + } + // path=d["path"]; } -Dictionary PackedScene::_get_bundled_scene() const { +Dictionary SceneState::get_bundled_scene() const { DVector<String> rnames; rnames.resize(names.size()); @@ -602,7 +1232,25 @@ Dictionary PackedScene::_get_bundled_scene() const { } d["conns"]=rconns; - d["version"]=1; + + Array rnode_paths; + rnode_paths.resize(node_paths.size()); + for(int i=0;i<node_paths.size();i++) { + rnode_paths[i]=node_paths[i]; + } + d["node_paths"]=rnode_paths; + + Array reditable_instances; + reditable_instances.resize(editable_instances.size()); + for(int i=0;i<editable_instances.size();i++) { + reditable_instances[i]=editable_instances[i]; + } + d["editable_instances"]=reditable_instances; + if (base_scene_idx>=0) { + d["base_scene"]=base_scene_idx; + } + + d["version"]=PACK_VERSION; // d["path"]=path; @@ -611,10 +1259,264 @@ Dictionary PackedScene::_get_bundled_scene() const { } +int SceneState::get_node_count() const { + + return nodes.size(); +} + +StringName SceneState::get_node_type(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName()); + if (nodes[p_idx].type==TYPE_INSTANCED) + return StringName(); + return names[nodes[p_idx].type]; +} + +StringName SceneState::get_node_name(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName()); + return names[nodes[p_idx].name]; +} + +Ref<PackedScene> SceneState::get_node_instance(int p_idx) const { + ERR_FAIL_INDEX_V(p_idx,nodes.size(),Ref<PackedScene>()); + if (nodes[p_idx].instance>=0) { + return variants[nodes[p_idx].instance]; + } else if (nodes[p_idx].parent<=0 || nodes[p_idx].parent==NO_PARENT_SAVED) { + + if (base_scene_idx>=0) { + return variants[base_scene_idx]; + } + } + + return Ref<PackedScene>(); + + +} +Vector<StringName> SceneState::get_node_groups(int p_idx) const{ + ERR_FAIL_INDEX_V(p_idx,nodes.size(),Vector<StringName>()); + Vector<StringName> groups; + for(int i=0;i<nodes[p_idx].groups.size();i++) { + groups.push_back(names[nodes[p_idx].groups[i]]); + } + return groups; +} + + +NodePath SceneState::get_node_path(int p_idx,bool p_for_parent) const { + + ERR_FAIL_INDEX_V(p_idx,nodes.size(),NodePath()); + + if (nodes[p_idx].parent<0 || nodes[p_idx].parent==NO_PARENT_SAVED) { + if (p_for_parent) { + return NodePath(); + } else { + return NodePath("."); + } + } + + Vector<StringName> sub_path; + NodePath base_path; + int nidx=p_idx; + while(true) { + if (nodes[nidx].parent==NO_PARENT_SAVED || nodes[nidx].parent<0) { + + sub_path.insert(0,"."); + break; + } + + if (!p_for_parent || p_idx!=nidx) { + sub_path.insert(0,names[nodes[nidx].name]); + } + + if (nodes[nidx].parent&FLAG_ID_IS_PATH) { + base_path=node_paths[nodes[nidx].parent&FLAG_MASK]; + break; + } else { + nidx=nodes[nidx].parent&FLAG_MASK; + } + } + + for(int i=0;i<base_path.get_name_count();i++) { + StringName sn = base_path.get_name(i); + sub_path.insert(0,base_path.get_name(i)); + } + + if (sub_path.empty()) { + return NodePath("."); + } + + return NodePath(sub_path,false); + +} + +int SceneState::get_node_property_count(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,nodes.size(),-1); + return nodes[p_idx].properties.size(); + +} +StringName SceneState::get_node_property_name(int p_idx,int p_prop) const{ + ERR_FAIL_INDEX_V(p_idx,nodes.size(),StringName()); + ERR_FAIL_INDEX_V(p_prop,nodes[p_idx].properties.size(),StringName()); + return names[nodes[p_idx].properties[p_prop].name]; + +} +Variant SceneState::get_node_property_value(int p_idx,int p_prop) const{ + ERR_FAIL_INDEX_V(p_idx,nodes.size(),Variant()); + ERR_FAIL_INDEX_V(p_prop,nodes[p_idx].properties.size(),Variant()); + + return variants[nodes[p_idx].properties[p_prop].value]; +} + + +NodePath SceneState::get_node_owner_path(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,nodes.size(),NodePath()); + if (nodes[p_idx].owner<0 || nodes[p_idx].owner==NO_PARENT_SAVED) + return NodePath(); //root likely + if (nodes[p_idx].owner&FLAG_ID_IS_PATH) { + return node_paths[nodes[p_idx].owner&FLAG_MASK]; + } else { + return get_node_path(nodes[p_idx].owner&FLAG_MASK); + } +} + +int SceneState::get_connection_count() const { + + return connections.size(); +} +NodePath SceneState::get_connection_source(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,connections.size(),NodePath()); + if (connections[p_idx].from&FLAG_ID_IS_PATH) { + return node_paths[connections[p_idx].from&FLAG_MASK]; + } else { + return get_node_path(connections[p_idx].from&FLAG_MASK); + } + +} + +StringName SceneState::get_connection_signal(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,connections.size(),StringName()); + return names[connections[p_idx].signal]; + +} +NodePath SceneState::get_connection_target(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,connections.size(),NodePath()); + if (connections[p_idx].to&FLAG_ID_IS_PATH) { + return node_paths[connections[p_idx].to&FLAG_MASK]; + } else { + return get_node_path(connections[p_idx].to&FLAG_MASK); + } + +} +StringName SceneState::get_connection_method(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,connections.size(),StringName()); + return names[connections[p_idx].method]; + +} +int SceneState::get_connection_flags(int p_idx) const{ + + ERR_FAIL_INDEX_V(p_idx,connections.size(),-1); + return connections[p_idx].flags; +} + +Array SceneState::get_connection_binds(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,connections.size(),-1); + Array binds; + for(int i=0;i<connections[p_idx].binds.size();i++) { + binds.push_back(variants[connections[p_idx].binds[i]]); + } + return binds; +} + +Vector<NodePath> SceneState::get_editable_instances() const { + return editable_instances; +} + + +SceneState::SceneState() { + + base_scene_idx=-1; +} + + +//////////////// + + + +void PackedScene::_set_bundled_scene(const Dictionary& d) { + + state->set_bundled_scene(d); +} + +Dictionary PackedScene::_get_bundled_scene() const { + + return state->get_bundled_scene(); +} + + +Error PackedScene::pack(Node *p_scene) { + + return state->pack(p_scene); +} + +void PackedScene::clear() { + + state->clear(); +} + +bool PackedScene::can_instance() const { + + return state->can_instance(); +} + +Node *PackedScene::instance(bool p_gen_edit_state) const { + +#ifndef TOOLS_ENABLED + if (p_gen_edit_state) { + ERR_EXPLAIN("Edit state is only for editors, does not work without tools compiled"); + ERR_FAIL_COND_V(p_gen_edit_state,NULL); + } +#endif + + Node *s = state->instance(p_gen_edit_state); + if (!s) + return NULL; + + if (p_gen_edit_state) { + s->set_scene_instance_state(state); + } + + if (get_path()!="" && get_path().find("::")==-1) + s->set_filename(get_path()); + + + s->notification(Node::NOTIFICATION_INSTANCED); + + return s; +} + +Ref<SceneState> PackedScene::get_state() { + + return state; +} + +void PackedScene::set_path(const String& p_path,bool p_take_over) { + + state->set_path(p_path); + Resource::set_path(p_path,p_take_over); +} + void PackedScene::_bind_methods() { ObjectTypeDB::bind_method(_MD("pack","path:Node"),&PackedScene::pack); - ObjectTypeDB::bind_method(_MD("instance:Node"),&PackedScene::instance,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("instance:Node","gen_edit_state"),&PackedScene::instance,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("can_instance"),&PackedScene::can_instance); ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&PackedScene::_set_bundled_scene); ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&PackedScene::_get_bundled_scene); @@ -625,5 +1527,6 @@ void PackedScene::_bind_methods() { PackedScene::PackedScene() { + state = Ref<SceneState>( memnew( SceneState )); } diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 6c7fa545d4..3956d2abe4 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -32,17 +32,27 @@ #include "resource.h" #include "scene/main/node.h" -class PackedScene : public Resource { - OBJ_TYPE( PackedScene, Resource ); - RES_BASE_EXTENSION("scn"); +class SceneState : public Reference { + + OBJ_TYPE( SceneState, Reference ); Vector<StringName> names; Vector<Variant> variants; + Vector<NodePath> node_paths; + Vector<NodePath> editable_instances; + mutable HashMap<NodePath,int> node_path_cache; + mutable Map<int,int> base_scene_node_remap; - //missing - instances - //missing groups - //missing - owner - //missing - override names and values + int base_scene_idx; + + enum { + FLAG_ID_IS_PATH=(1<<30), + FLAG_INSTANCE_IS_PLACEHOLDER=(1<<30), + FLAG_MASK=(1<<24)-1, + NO_PARENT_SAVED=0x7FFFFFFF, + TYPE_INSTANCED=0x7FFFFFFF, + + }; struct NodeData { @@ -59,9 +69,15 @@ class PackedScene : public Resource { }; Vector<Property> properties; - Vector<int> groups; + Vector<int> groups; + }; + struct PackState { + Ref<SceneState> state; + int node; + PackState() { node=-1; } + }; Vector<NodeData> nodes; @@ -77,16 +93,78 @@ class PackedScene : public Resource { Vector<ConnectionData> connections; - Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map); - Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map); + Error _parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map); + Error _parse_connections(Node *p_owner,Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,Map<Node*,int> &nodepath_map); + + String path; + + _FORCE_INLINE_ Ref<SceneState> _get_base_scene_state() const; + + static bool disable_placeholders; +public: + + static void set_disable_placeholders(bool p_disable); + + int find_node_by_path(const NodePath& p_node) const; + Variant get_property_value(int p_node,const StringName& p_property,bool &found) const; + bool is_node_in_group(int p_node,const StringName& p_group) const; + bool is_connection(int p_node,const StringName& p_signal,int p_to_node,const StringName& p_to_method) const; + + + void set_bundled_scene(const Dictionary& p_dictionary); + Dictionary get_bundled_scene() const; + + Error pack(Node *p_scene); + + void set_path(const String &p_path); + String get_path() const; + + void clear(); + + bool can_instance() const; + Node *instance(bool p_gen_edit_state=false) const; + + + //build-unbuild API + + int get_node_count() const; + StringName get_node_type(int p_idx) const; + StringName get_node_name(int p_idx) const; + NodePath get_node_path(int p_idx,bool p_for_parent=false) const; + NodePath get_node_owner_path(int p_idx) const; + Ref<PackedScene> get_node_instance(int p_idx) const; + Vector<StringName> get_node_groups(int p_idx) const; + + int get_node_property_count(int p_idx) const; + StringName get_node_property_name(int p_idx,int p_prop) const; + Variant get_node_property_value(int p_idx,int p_prop) const; + + int get_connection_count() const; + NodePath get_connection_source(int p_idx) const; + StringName get_connection_signal(int p_idx) const; + NodePath get_connection_target(int p_idx) const; + StringName get_connection_method(int p_idx) const; + int get_connection_flags(int p_idx) const; + Array get_connection_binds(int p_idx) const; + + Vector<NodePath> get_editable_instances() const; + + SceneState(); +}; + +class PackedScene : public Resource { + + OBJ_TYPE(PackedScene, Resource ); + RES_BASE_EXTENSION("scn"); + + Ref<SceneState> state; void _set_bundled_scene(const Dictionary& p_scene); Dictionary _get_bundled_scene() const; protected: - static void _bind_methods(); public: @@ -98,7 +176,12 @@ public: bool can_instance() const; Node *instance(bool p_gen_edit_state=false) const; + virtual void set_path(const String& p_path,bool p_take_over=false); + + Ref<SceneState> get_state(); + PackedScene(); + }; #endif // SCENE_PRELOADER_H 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/sample_library.cpp b/scene/resources/sample_library.cpp index 6bb9bc0d06..ffcaa1e675 100644 --- a/scene/resources/sample_library.cpp +++ b/scene/resources/sample_library.cpp @@ -34,7 +34,7 @@ bool SampleLibrary::_set(const StringName& p_name, const Variant& p_value) { if (String(p_name).begins_with("samples/")) { - String name=String(p_name).get_slice("/",1); + String name=String(p_name).get_slicec('/',1); if (p_value.get_type()==Variant::NIL) sample_map.erase(name); else { @@ -66,7 +66,7 @@ bool SampleLibrary::_get(const StringName& p_name,Variant &r_ret) const { if (String(p_name).begins_with("samples/")) { - String name=String(p_name).get_slice("/",1); + String name=String(p_name).get_slicec('/',1); if(sample_map.has(name)) { Dictionary d; d["sample"]=sample_map[name].sample; diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp new file mode 100644 index 0000000000..8403c06ad1 --- /dev/null +++ b/scene/resources/scene_format_text.cpp @@ -0,0 +1,792 @@ +#include "scene_format_text.h" + +#include "globals.h" +#include "version.h" +#include "os/dir_access.h" + +#define FORMAT_VERSION 1 + +void ResourceFormatSaverTextInstance::write_property(const String& p_name,const Variant& p_property,bool *r_ok) { + + if (r_ok) + *r_ok=false; + + if (p_name!=String()) { + f->store_string(p_name+" = "); + } + + switch( p_property.get_type() ) { + + case Variant::NIL: { + f->store_string("null"); + } break; + case Variant::BOOL: { + + f->store_string(p_property.operator bool() ? "true":"false" ); + } break; + case Variant::INT: { + + f->store_string( itos(p_property.operator int()) ); + } break; + case Variant::REAL: { + + f->store_string( rtoss(p_property.operator real_t()) ); + } break; + case Variant::STRING: { + + String str=p_property; + + str="\""+str.c_escape()+"\""; + f->store_string( str ); + } break; + case Variant::VECTOR2: { + + Vector2 v = p_property; + f->store_string("Vector2( "+rtoss(v.x) +", "+rtoss(v.y)+" )" ); + } break; + case Variant::RECT2: { + + Rect2 aabb = p_property; + f->store_string("Rect2( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y)+" )" ); + + } break; + case Variant::VECTOR3: { + + Vector3 v = p_property; + f->store_string("Vector3( "+rtoss(v.x) +", "+rtoss(v.y)+", "+rtoss(v.z)+" )"); + } break; + case Variant::PLANE: { + + Plane p = p_property; + f->store_string("Plane( "+rtoss(p.normal.x) +", "+rtoss(p.normal.y)+", "+rtoss(p.normal.z)+", "+rtoss(p.d)+" )" ); + + } break; + case Variant::_AABB: { + + AABB aabb = p_property; + f->store_string("AABB( "+rtoss(aabb.pos.x) +", "+rtoss(aabb.pos.y) +", "+rtoss(aabb.pos.z) +", "+rtoss(aabb.size.x) +", "+rtoss(aabb.size.y) +", "+rtoss(aabb.size.z)+" )" ); + + } break; + case Variant::QUAT: { + + Quat quat = p_property; + f->store_string("Quat( "+rtoss(quat.x)+", "+rtoss(quat.y)+", "+rtoss(quat.z)+", "+rtoss(quat.w)+" )"); + + } break; + case Variant::MATRIX32: { + + String s="Matrix32( "; + Matrix32 m3 = p_property; + for (int i=0;i<3;i++) { + for (int j=0;j<2;j++) { + + if (i!=0 || j!=0) + s+=", "; + s+=rtoss( m3.elements[i][j] ); + } + } + + f->store_string(s+" )"); + + } break; + case Variant::MATRIX3: { + + String s="Matrix3( "; + Matrix3 m3 = p_property; + for (int i=0;i<3;i++) { + for (int j=0;j<3;j++) { + + if (i!=0 || j!=0) + s+=", "; + s+=rtoss( m3.elements[i][j] ); + } + } + + f->store_string(s+" )"); + + } break; + case Variant::TRANSFORM: { + + String s="Transform( "; + Transform t = p_property; + Matrix3 &m3 = t.basis; + for (int i=0;i<3;i++) { + for (int j=0;j<3;j++) { + + if (i!=0 || j!=0) + s+=", "; + s+=rtoss( m3.elements[i][j] ); + } + } + + s=s+", "+rtoss(t.origin.x) +", "+rtoss(t.origin.y)+", "+rtoss(t.origin.z); + + f->store_string(s+" )"); + } break; + + // misc types + case Variant::COLOR: { + + Color c = p_property; + f->store_string("Color( "+rtoss(c.r) +", "+rtoss(c.g)+", "+rtoss(c.b)+", "+rtoss(c.a)+" )"); + + } break; + case Variant::IMAGE: { + + + Image img=p_property; + + if (img.empty()) { + f->store_string("RawImage()"); + break; + } + + String imgstr="RawImage( "; + imgstr+=itos(img.get_width()); + imgstr+=", "+itos(img.get_height()); + imgstr+=", "+itos(img.get_mipmaps()); + imgstr+=", "; + + switch(img.get_format()) { + + case Image::FORMAT_GRAYSCALE: imgstr+="GRAYSCALE"; break; + case Image::FORMAT_INTENSITY: imgstr+="INTENSITY"; break; + case Image::FORMAT_GRAYSCALE_ALPHA: imgstr+="GRAYSCALE_ALPHA"; break; + case Image::FORMAT_RGB: imgstr+="RGB"; break; + case Image::FORMAT_RGBA: imgstr+="RGBA"; break; + case Image::FORMAT_INDEXED : imgstr+="INDEXED"; break; + case Image::FORMAT_INDEXED_ALPHA: imgstr+="INDEXED_ALPHA"; break; + case Image::FORMAT_BC1: imgstr+="BC1"; break; + case Image::FORMAT_BC2: imgstr+="BC2"; break; + case Image::FORMAT_BC3: imgstr+="BC3"; break; + case Image::FORMAT_BC4: imgstr+="BC4"; break; + case Image::FORMAT_BC5: imgstr+="BC5"; break; + case Image::FORMAT_PVRTC2: imgstr+="PVRTC2"; break; + case Image::FORMAT_PVRTC2_ALPHA: imgstr+="PVRTC2_ALPHA"; break; + case Image::FORMAT_PVRTC4: imgstr+="PVRTC4"; break; + case Image::FORMAT_PVRTC4_ALPHA: imgstr+="PVRTC4_ALPHA"; break; + case Image::FORMAT_ETC: imgstr+="ETC"; break; + case Image::FORMAT_ATC: imgstr+="ATC"; break; + case Image::FORMAT_ATC_ALPHA_EXPLICIT: imgstr+="ATC_ALPHA_EXPLICIT"; break; + case Image::FORMAT_ATC_ALPHA_INTERPOLATED: imgstr+="ATC_ALPHA_INTERPOLATED"; break; + case Image::FORMAT_CUSTOM: imgstr+="CUSTOM"; break; + default: {} + } + + + String s; + + DVector<uint8_t> data = img.get_data(); + int len = data.size(); + DVector<uint8_t>::Read r = data.read(); + const uint8_t *ptr=r.ptr();; + for (int i=0;i<len;i++) { + + uint8_t byte = ptr[i]; + const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + char str[3]={ hex[byte>>4], hex[byte&0xF], 0}; + s+=str; + } + + imgstr+=", "; + f->store_string(imgstr); + f->store_string(s); + f->store_string(" )"); + } break; + case Variant::NODE_PATH: { + + String str=p_property; + + str="NodePath(\""+str.c_escape()+"\")"; + f->store_string(str); + + } break; + + case Variant::OBJECT: { + + RES res = p_property; + if (res.is_null()) { + f->store_string("null"); + if (r_ok) + *r_ok=true; + + break; // don't save it + } + + if (external_resources.has(res)) { + + f->store_string("ExtResource( "+itos(external_resources[res]+1)+" )"); + } else { + + if (internal_resources.has(res)) { + f->store_string("SubResource( "+itos(internal_resources[res])+" )"); + } else if (res->get_path().length() && res->get_path().find("::")==-1) { + + //external resource + String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); + f->store_string("Resource( \""+path+"\" )"); + } else { + f->store_string("null"); + ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); + ERR_BREAK(true); + //internal resource + } + } + + } break; + case Variant::INPUT_EVENT: { + + f->store_string("InputEvent()"); //will be added later + } break; + case Variant::DICTIONARY: { + + Dictionary dict = p_property; + + List<Variant> keys; + dict.get_key_list(&keys); + keys.sort(); + + f->store_string("{ "); + for(List<Variant>::Element *E=keys.front();E;E=E->next()) { + + //if (!_check_type(dict[E->get()])) + // continue; + bool ok; + write_property("",E->get(),&ok); + ERR_CONTINUE(!ok); + + f->store_string(":"); + write_property("",dict[E->get()],&ok); + if (!ok) + write_property("",Variant()); //at least make the file consistent.. + if (E->next()) + f->store_string(", "); + } + + + f->store_string(" }"); + + + } break; + case Variant::ARRAY: { + + f->store_string("[ "); + Array array = p_property; + int len=array.size(); + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + write_property("",array[i]); + + + } + f->store_string(" ]"); + + } break; + + case Variant::RAW_ARRAY: { + + f->store_string("RawArray( "); + String s; + DVector<uint8_t> data = p_property; + int len = data.size(); + DVector<uint8_t>::Read r = data.read(); + const uint8_t *ptr=r.ptr();; + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + uint8_t byte = ptr[i]; + const char hex[16]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + char str[3]={ hex[byte>>4], hex[byte&0xF], 0}; + f->store_string(str); + + } + + f->store_string(" )"); + + } break; + case Variant::INT_ARRAY: { + + f->store_string("IntArray( "); + DVector<int> data = p_property; + int len = data.size(); + DVector<int>::Read r = data.read(); + const int *ptr=r.ptr();; + + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + + f->store_string(itos(ptr[i])); + } + + + f->store_string(" )"); + + } break; + case Variant::REAL_ARRAY: { + + f->store_string("FloatArray( "); + DVector<real_t> data = p_property; + int len = data.size(); + DVector<real_t>::Read r = data.read(); + const real_t *ptr=r.ptr();; + + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + f->store_string(rtoss(ptr[i])); + } + + f->store_string(" )"); + + } break; + case Variant::STRING_ARRAY: { + + f->store_string("StringArray( "); + DVector<String> data = p_property; + int len = data.size(); + DVector<String>::Read r = data.read(); + const String *ptr=r.ptr();; + String s; + //write_string("\n"); + + + + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + String str=ptr[i]; + f->store_string(""+str.c_escape()+"\""); + } + + f->store_string(" )"); + + } break; + case Variant::VECTOR2_ARRAY: { + + f->store_string("Vector2Array( "); + DVector<Vector2> data = p_property; + int len = data.size(); + DVector<Vector2>::Read r = data.read(); + const Vector2 *ptr=r.ptr();; + + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y) ); + } + + f->store_string(" )"); + + } break; + case Variant::VECTOR3_ARRAY: { + + f->store_string("Vector3Array( "); + DVector<Vector3> data = p_property; + int len = data.size(); + DVector<Vector3>::Read r = data.read(); + const Vector3 *ptr=r.ptr();; + + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + f->store_string(rtoss(ptr[i].x)+", "+rtoss(ptr[i].y)+", "+rtoss(ptr[i].z) ); + } + + f->store_string(" )"); + + } break; + case Variant::COLOR_ARRAY: { + + f->store_string("ColorArray( "); + + DVector<Color> data = p_property; + int len = data.size(); + DVector<Color>::Read r = data.read(); + const Color *ptr=r.ptr();; + + for (int i=0;i<len;i++) { + + if (i>0) + f->store_string(", "); + + f->store_string(rtoss(ptr[i].r)+", "+rtoss(ptr[i].g)+", "+rtoss(ptr[i].b)+", "+rtoss(ptr[i].a) ); + + } + f->store_string(" )"); + + } break; + default: {} + + } + + if (r_ok) + *r_ok=true; + +} + + +void ResourceFormatSaverTextInstance::_find_resources(const Variant& p_variant,bool p_main) { + + + switch(p_variant.get_type()) { + case Variant::OBJECT: { + + + RES res = p_variant.operator RefPtr(); + + if (res.is_null() || external_resources.has(res)) + return; + + if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { + int index = external_resources.size(); + external_resources[res]=index; + return; + } + + if (resource_set.has(res)) + return; + + List<PropertyInfo> property_list; + + res->get_property_list( &property_list ); + property_list.sort(); + + List<PropertyInfo>::Element *I=property_list.front(); + + while(I) { + + PropertyInfo pi=I->get(); + + if (pi.usage&PROPERTY_USAGE_STORAGE || (bundle_resources && pi.usage&PROPERTY_USAGE_BUNDLE)) { + + Variant v=res->get(I->get().name); + _find_resources(v); + } + + I=I->next(); + } + + resource_set.insert( res ); //saved after, so the childs it needs are available when loaded + saved_resources.push_back(res); + + } break; + case Variant::ARRAY: { + + Array varray=p_variant; + int len=varray.size(); + for(int i=0;i<len;i++) { + + Variant v=varray.get(i); + _find_resources(v); + } + + } break; + case Variant::DICTIONARY: { + + Dictionary d=p_variant; + List<Variant> keys; + d.get_key_list(&keys); + for(List<Variant>::Element *E=keys.front();E;E=E->next()) { + + Variant v = d[E->get()]; + _find_resources(v); + } + } break; + default: {} + } + +} + + + +Error ResourceFormatSaverTextInstance::save(const String &p_path,const RES& p_resource,uint32_t p_flags) { + + if (p_path.ends_with(".tscn")) { + packed_scene=p_resource; + } + + Error err; + f = FileAccess::open(p_path, FileAccess::WRITE,&err); + ERR_FAIL_COND_V( err, ERR_CANT_OPEN ); + FileAccessRef _fref(f); + + local_path = Globals::get_singleton()->localize_path(p_path); + + relative_paths=p_flags&ResourceSaver::FLAG_RELATIVE_PATHS; + skip_editor=p_flags&ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES; + bundle_resources=p_flags&ResourceSaver::FLAG_BUNDLE_RESOURCES; + takeover_paths=p_flags&ResourceSaver::FLAG_REPLACE_SUBRESOURCE_PATHS; + if (!p_path.begins_with("res://")) { + takeover_paths=false; + } + + // save resources + _find_resources(p_resource,true); + + if (packed_scene.is_valid()) { + //add instances to external resources if saving a packed scene + for(int i=0;i<packed_scene->get_state()->get_node_count();i++) { + Ref<PackedScene> instance=packed_scene->get_state()->get_node_instance(i); + if (instance.is_valid() && !external_resources.has(instance)) { + int index = external_resources.size(); + external_resources[instance]=index; + } + } + } + + + ERR_FAIL_COND_V(err!=OK,err); + + { + String title=packed_scene.is_valid()?"[gd_scene ":"[gd_resource "; + if (packed_scene.is_null()) + title+="type=\""+p_resource->get_type()+"\" "; + int load_steps=saved_resources.size()+external_resources.size(); + //if (packed_scene.is_valid()) { + // load_steps+=packed_scene->get_node_count(); + //} + //no, better to not use load steps from nodes, no point to that + + if (load_steps>1) { + title+="load_steps="+itos(load_steps)+" "; + } + title+="format="+itos(FORMAT_VERSION)+""; + //title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\""; + + f->store_string(title); + f->store_line("]\n"); //one empty line + } + + + for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) { + + String p = E->key()->get_path(); + + f->store_string("[ext_resource path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" id="+itos(E->get()+1)+"]\n"); //bundled + } + + if (external_resources.size()) + f->store_line(String()); //separate + + Set<int> used_indices; + + for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) { + + RES res = E->get(); + if (E->next() && (res->get_path()=="" || res->get_path().find("::") != -1 )) { + + if (res->get_subindex()!=0) { + if (used_indices.has(res->get_subindex())) { + res->set_subindex(0); //repeated + } else { + used_indices.insert(res->get_subindex()); + } + } + } + } + + for(List<RES>::Element *E=saved_resources.front();E;E=E->next()) { + + RES res = E->get(); + ERR_CONTINUE(!resource_set.has(res)); + bool main = (E->next()==NULL); + + if (main && packed_scene.is_valid()) + break; //save as a scene + + if (main) { + f->store_line("[resource]\n"); + } else { + String line="[sub_resource "; + if (res->get_subindex()==0) { + int new_subindex=1; + if (used_indices.size()) { + new_subindex=used_indices.back()->get()+1; + } + + res->set_subindex(new_subindex); + used_indices.insert(new_subindex); + } + + int idx = res->get_subindex(); + line+="type=\""+res->get_type()+"\" id="+itos(idx); + f->store_line(line+"]\n"); + if (takeover_paths) { + res->set_path(p_path+"::"+itos(idx),true); + } + + internal_resources[res]=idx; + + } + + + List<PropertyInfo> property_list; + res->get_property_list(&property_list); +// property_list.sort(); + for(List<PropertyInfo>::Element *PE = property_list.front();PE;PE=PE->next()) { + + + if (skip_editor && PE->get().name.begins_with("__editor")) + continue; + + if (PE->get().usage&PROPERTY_USAGE_STORAGE || (bundle_resources && PE->get().usage&PROPERTY_USAGE_BUNDLE)) { + + String name = PE->get().name; + Variant value = res->get(name); + + + if ((PE->get().usage&PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero())||(PE->get().usage&PROPERTY_USAGE_STORE_IF_NONONE && value.is_one()) ) + continue; + + if (PE->get().type==Variant::OBJECT && value.is_zero()) + continue; + + write_property(name,value); + f->store_string("\n"); + } + + + } + + f->store_string("\n"); + + } + + if (packed_scene.is_valid()) { + //if this is a scene, save nodes and connections! + Ref<SceneState> state = packed_scene->get_state(); + for(int i=0;i<state->get_node_count();i++) { + + StringName type = state->get_node_type(i); + StringName name = state->get_node_name(i); + NodePath path = state->get_node_path(i,true); + NodePath owner = state->get_node_owner_path(i); + Ref<PackedScene> instance = state->get_node_instance(i); + Vector<StringName> groups = state->get_node_groups(i); + + String header="[node"; + header+=" name=\""+String(name)+"\""; + if (type!=StringName()) { + header+=" type=\""+String(type)+"\""; + } + if (path!=NodePath()) { + header+=" parent=\""+String(path.simplified())+"\""; + } + if (owner!=NodePath() && owner!=NodePath(".")) { + header+=" owner=\""+String(owner.simplified())+"\""; + } + + if (groups.size()) { + String sgroups=" groups=[ "; + for(int j=0;j<groups.size();j++) { + if (j>0) + sgroups+=", "; + sgroups+="\""+groups[i].operator String().c_escape()+"\""; + } + sgroups+=" ]"; + header+=sgroups; + } + + f->store_string(header); + + if (instance.is_valid()) { + f->store_string(" instance="); + write_property("",instance); + } + + f->store_line("]\n"); + + for(int j=0;j<state->get_node_property_count(i);j++) { + + write_property(state->get_node_property_name(i,j),state->get_node_property_value(i,j)); + f->store_line(String()); + + } + + if (state->get_node_property_count(i)) { + //add space + f->store_line(String()); + } + + } + + for(int i=0;i<state->get_connection_count();i++) { + + String connstr="[connection"; + connstr+=" signal=\""+String(state->get_connection_signal(i))+"\""; + connstr+=" from=\""+String(state->get_connection_source(i).simplified())+"\""; + connstr+=" to=\""+String(state->get_connection_target(i).simplified())+"\""; + connstr+=" method=\""+String(state->get_connection_method(i))+"\""; + int flags = state->get_connection_flags(i); + if (flags!=Object::CONNECT_PERSIST) { + connstr+=" flags="+itos(flags); + } + + Array binds=state->get_connection_binds(i); + f->store_string(connstr); + if (binds.size()) { + f->store_string(" binds="); + write_property("",binds); + } + + f->store_line("]\n"); + } + + f->store_line(String()); + + Vector<NodePath> editable_instances = state->get_editable_instances(); + for(int i=0;i<editable_instances.size();i++) { + f->store_line("[editable path=\""+editable_instances[i].operator String()+"\"]"); + } + } + + if (f->get_error()!=OK && f->get_error()!=ERR_FILE_EOF) { + f->close(); + return ERR_CANT_CREATE; + } + + f->close(); + //memdelete(f); + + return OK; +} + + + +Error ResourceFormatSaverText::save(const String &p_path,const RES& p_resource,uint32_t p_flags) { + + if (p_path.ends_with(".sct") && p_resource->get_type()!="PackedScene") { + return ERR_FILE_UNRECOGNIZED; + } + + ResourceFormatSaverTextInstance saver; + return saver.save(p_path,p_resource,p_flags); + +} + +bool ResourceFormatSaverText::recognize(const RES& p_resource) const { + + + return true; // all recognized! +} +void ResourceFormatSaverText::get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const { + + p_extensions->push_back("tres"); //text resource + if (p_resource->get_type()=="PackedScene") + p_extensions->push_back("tscn"); //text scene + +} + +ResourceFormatSaverText* ResourceFormatSaverText::singleton=NULL; +ResourceFormatSaverText::ResourceFormatSaverText() { + singleton=this; +} diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h new file mode 100644 index 0000000000..576a78d183 --- /dev/null +++ b/scene/resources/scene_format_text.h @@ -0,0 +1,46 @@ +#ifndef SCENE_FORMAT_TEXT_H +#define SCENE_FORMAT_TEXT_H + +#include "io/resource_loader.h" +#include "io/resource_saver.h" +#include "os/file_access.h" +#include "scene/resources/packed_scene.h" + +class ResourceFormatSaverTextInstance { + + String local_path; + + Ref<PackedScene> packed_scene; + + bool takeover_paths; + bool relative_paths; + bool bundle_resources; + bool skip_editor; + FileAccess *f; + Set<RES> resource_set; + List<RES> saved_resources; + Map<RES,int> external_resources; + Map<RES,int> internal_resources; + + void _find_resources(const Variant& p_variant,bool p_main=false); + void write_property(const String& p_name,const Variant& p_property,bool *r_ok=NULL); + +public: + + Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0); + + +}; + +class ResourceFormatSaverText : public ResourceFormatSaver { +public: + static ResourceFormatSaverText* singleton; + virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0); + virtual bool recognize(const RES& p_resource) const; + virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const; + + ResourceFormatSaverText(); +}; + + +#endif // SCENE_FORMAT_TEXT_H 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/shader.cpp b/scene/resources/shader.cpp index 90598ee789..a9376faf62 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -219,7 +219,10 @@ Shader::~Shader() { -RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderShader::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; String fragment_code; String vertex_code; @@ -235,6 +238,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin ERR_FAIL_COND_V(err,RES()); String base_path = p_path.get_base_dir(); + if (r_error) + *r_error=ERR_FILE_CORRUPT; Ref<Shader> shader;//( memnew( Shader ) ); @@ -435,6 +440,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin f->close(); memdelete(f); + if (r_error) + *r_error=OK; return shader; } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index b805cbec96..61a369c408 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -126,7 +126,7 @@ public: class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; 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/texture.cpp b/scene/resources/texture.cpp index 018af0e5db..7b261f7791 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -81,6 +81,7 @@ void Texture::_bind_methods() { BIND_CONSTANT( FLAGS_DEFAULT ); BIND_CONSTANT( FLAG_ANISOTROPIC_FILTER ); BIND_CONSTANT( FLAG_CONVERT_TO_LINEAR ); + BIND_CONSTANT( FLAG_MIRRORED_REPEAT ); } @@ -181,7 +182,7 @@ void ImageTexture::_get_property_list( List<PropertyInfo> *p_list) const { - p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB") ); + p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat") ); p_list->push_back( PropertyInfo( Variant::IMAGE, "image", img_hint,String::num(lossy_storage_quality)) ); p_list->push_back( PropertyInfo( Variant::VECTOR2, "size",PROPERTY_HINT_NONE, "")); p_list->push_back( PropertyInfo( Variant::INT, "storage", PROPERTY_HINT_ENUM,"Uncompressed,Compress Lossy,Compress Lossless")); diff --git a/scene/resources/texture.h b/scene/resources/texture.h index 9be8e24a83..ad0e21093d 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -56,6 +56,7 @@ public: FLAG_CONVERT_TO_LINEAR=VisualServer::TEXTURE_FLAG_CONVERT_TO_LINEAR, FLAG_VIDEO_SURFACE=VisualServer::TEXTURE_FLAG_VIDEO_SURFACE, FLAGS_DEFAULT=FLAG_MIPMAPS|FLAG_REPEAT|FLAG_FILTER, + FLAG_MIRRORED_REPEAT=VisualServer::TEXTURE_FLAG_MIRRORED_REPEAT }; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 21bdb6c0ab..651e234b49 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -40,9 +40,9 @@ bool Theme::_set(const StringName& p_name, const Variant& p_value) { if (sname.find("/")!=-1) { - String type=sname.get_slice("/",1); - String node_type=sname.get_slice("/",0); - String name=sname.get_slice("/",2); + String type=sname.get_slicec('/',1); + String node_type=sname.get_slicec('/',0); + String name=sname.get_slicec('/',2); if (type=="icons") { @@ -75,9 +75,9 @@ bool Theme::_get(const StringName& p_name,Variant &r_ret) const { if (sname.find("/")!=-1) { - String type=sname.get_slice("/",1); - String node_type=sname.get_slice("/",0); - String name=sname.get_slice("/",2); + String type=sname.get_slicec('/',1); + String node_type=sname.get_slicec('/',0); + String name=sname.get_slicec('/',2); if (type=="icons") { @@ -601,7 +601,9 @@ Theme::~Theme() -RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderTheme::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -611,6 +613,8 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina String base_path = p_path.get_base_dir(); Ref<Theme> theme( memnew( Theme ) ); Map<StringName,Variant> library; + if (r_error) + *r_error=ERR_FILE_CORRUPT; bool reading_library=false; int line=0; @@ -1003,6 +1007,9 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina f->close(); memdelete(f); + if (r_error) + *r_error=OK; + return theme; } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 802dcb099c..cfa0762595 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -124,7 +124,7 @@ public: class ResourceFormatLoaderTheme : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; 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 diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 2689c14718..9509878dc9 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -68,6 +68,8 @@ SceneStringNames::SceneStringNames() { area_enter_shape = StaticCString::create("area_enter_shape"); area_exit_shape = StaticCString::create("area_exit_shape"); + _body_inout = StaticCString::create("_body_inout"); + _area_inout = StaticCString::create("_area_inout"); idle=StaticCString::create("idle"); iteration=StaticCString::create("iteration"); @@ -161,4 +163,11 @@ SceneStringNames::SceneStringNames() { frame_changed=StaticCString::create("frame_changed"); + playback_speed=StaticCString::create("playback/speed"); + playback_active=StaticCString::create("playback/active"); + autoplay=StaticCString::create("autoplay"); + blend_times=StaticCString::create("blend_times"); + speed=StaticCString::create("speed"); + + path_pp=NodePath(".."); } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index 83e817dbf7..48f17ed38b 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -30,7 +30,7 @@ #define SCENE_STRING_NAMES_H #include "string_db.h" - +#include "path_db.h" class SceneStringNames { friend void register_scene_types(); @@ -87,6 +87,8 @@ public: StringName area_enter_shape; StringName area_exit_shape; + StringName _body_inout; + StringName _area_inout; StringName _get_gizmo_geometry; @@ -170,6 +172,14 @@ public: StringName frame_changed; + StringName playback_speed; + StringName playback_active; + StringName autoplay; + StringName blend_times; + StringName speed; + + NodePath path_pp; + }; |