diff options
Diffstat (limited to 'scene')
189 files changed, 11362 insertions, 8480 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp index 316dffb3f9..2fcfc18429 100644 --- a/scene/2d/animated_sprite.cpp +++ b/scene/2d/animated_sprite.cpp @@ -27,7 +27,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "animated_sprite.h" - +#include "scene/scene_string_names.h" void AnimatedSprite::edit_set_pivot(const Point2& p_pivot) { set_offset(p_pivot); @@ -207,7 +207,7 @@ void AnimatedSprite::set_frame(int p_frame) { frame=p_frame; update(); _change_notify("frame"); - + emit_signal(SceneStringNames::get_singleton()->frame_changed); } int AnimatedSprite::get_frame() const { @@ -233,6 +233,7 @@ void AnimatedSprite::set_offset(const Point2& p_offset) { offset=p_offset; update(); item_rect_changed(); + _change_notify("offset"); } Point2 AnimatedSprite::get_offset() const { @@ -325,6 +326,8 @@ void AnimatedSprite::_bind_methods() { ObjectTypeDB::bind_method(_MD("_res_changed"),&AnimatedSprite::_res_changed); + ADD_SIGNAL(MethodInfo("frame_changed")); + 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"), _SCS("set_frame"),_SCS("get_frame")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "centered"), _SCS("set_centered"),_SCS("is_centered")); diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp index ad228662e4..fce21f6001 100644 --- a/scene/2d/area_2d.cpp +++ b/scene/2d/area_2d.cpp @@ -73,14 +73,25 @@ real_t Area2D::get_gravity() const{ return gravity; } -void Area2D::set_density(real_t p_density){ +void Area2D::set_linear_damp(real_t p_linear_damp){ - density=p_density; - Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_DENSITY,p_density); + linear_damp=p_linear_damp; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_LINEAR_DAMP,p_linear_damp); } -real_t Area2D::get_density() const{ +real_t Area2D::get_linear_damp() const{ - return density; + return linear_damp; +} + +void Area2D::set_angular_damp(real_t p_angular_damp){ + + angular_damp=p_angular_damp; + Physics2DServer::get_singleton()->area_set_param(get_rid(),Physics2DServer::AREA_PARAM_ANGULAR_DAMP,p_angular_damp); +} + +real_t Area2D::get_angular_damp() const{ + + return angular_damp; } void Area2D::set_priority(real_t p_priority){ @@ -94,7 +105,7 @@ real_t Area2D::get_priority() const{ } -void Area2D::_body_enter_scene(ObjectID p_id) { +void Area2D::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = obj ? obj->cast_to<Node>() : NULL; @@ -102,9 +113,9 @@ void Area2D::_body_enter_scene(ObjectID p_id) { Map<ObjectID,BodyState>::Element *E=body_map.find(p_id); ERR_FAIL_COND(!E); - ERR_FAIL_COND(E->get().in_scene); + ERR_FAIL_COND(E->get().in_tree); - E->get().in_scene=true; + E->get().in_tree=true; emit_signal(SceneStringNames::get_singleton()->body_enter,node); for(int i=0;i<E->get().shapes.size();i++) { @@ -113,15 +124,15 @@ void Area2D::_body_enter_scene(ObjectID p_id) { } -void Area2D::_body_exit_scene(ObjectID p_id) { +void Area2D::_body_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,BodyState>::Element *E=body_map.find(p_id); ERR_FAIL_COND(!E); - ERR_FAIL_COND(!E->get().in_scene); - E->get().in_scene=false; + ERR_FAIL_COND(!E->get().in_tree); + E->get().in_tree=false; emit_signal(SceneStringNames::get_singleton()->body_exit,node); for(int i=0;i<E->get().shapes.size();i++) { @@ -142,16 +153,18 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b ERR_FAIL_COND(!body_in && !E); + locked=true; + if (body_in) { if (!E) { E = body_map.insert(objid,BodyState()); E->get().rc=0; - E->get().in_scene=node && node->is_inside_scene(); + E->get().in_tree=node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); - if (E->get().in_scene) { + node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid)); + if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_enter,node); } } @@ -162,7 +175,7 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b E->get().shapes.insert(ShapePair(p_body_shape,p_area_shape)); - if (E->get().in_scene) { + if (!node || E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_area_shape); } @@ -178,9 +191,9 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b if (E->get().rc==0) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); - node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); - if (E->get().in_scene) + 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); + if (E->get().in_tree) emit_signal(SceneStringNames::get_singleton()->body_exit,obj); } @@ -188,7 +201,7 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b eraseit=true; } - if (node && E->get().in_scene) { + if (!node || E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_area_shape); } @@ -197,11 +210,18 @@ void Area2D::_body_inout(int p_status,const RID& p_body, int p_instance, int p_b } + locked=false; + + } void Area2D::_clear_monitoring() { + if (locked) { + ERR_EXPLAIN("This function can't be used during the in/out signal."); + } + ERR_FAIL_COND(locked); Map<ObjectID,BodyState> bmcopy = body_map; body_map.clear(); @@ -212,7 +232,7 @@ void Area2D::_clear_monitoring() { Object *obj = ObjectDB::get_instance(E->key()); Node *node = obj ? obj->cast_to<Node>() : NULL; ERR_CONTINUE(!node); - if (!E->get().in_scene) + if (!E->get().in_tree) continue; for(int i=0;i<E->get().shapes.size();i++) { @@ -222,8 +242,8 @@ void Area2D::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->body_exit,obj); - node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); - node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + 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); } } @@ -232,7 +252,7 @@ void Area2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { _clear_monitoring(); } break; @@ -243,6 +263,11 @@ void Area2D::_notification(int p_what) { void Area2D::set_enable_monitoring(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==monitoring) return; @@ -263,11 +288,30 @@ bool Area2D::is_monitoring_enabled() const { return monitoring; } +Array Area2D::get_overlapping_bodies() const { + + ERR_FAIL_COND_V(!monitoring,Array()); + Array ret; + ret.resize(body_map.size()); + int idx=0; + for (const Map<ObjectID,BodyState>::Element *E=body_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; +} + void Area2D::_bind_methods() { - ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area2D::_body_enter_scene); - ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area2D::_body_exit_scene); + ObjectTypeDB::bind_method(_MD("_body_enter_tree","id"),&Area2D::_body_enter_tree); + ObjectTypeDB::bind_method(_MD("_body_exit_tree","id"),&Area2D::_body_exit_tree); ObjectTypeDB::bind_method(_MD("set_space_override_mode","enable"),&Area2D::set_space_override_mode); ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area2D::get_space_override_mode); @@ -281,8 +325,11 @@ void Area2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_gravity","gravity"),&Area2D::set_gravity); ObjectTypeDB::bind_method(_MD("get_gravity"),&Area2D::get_gravity); - ObjectTypeDB::bind_method(_MD("set_density","density"),&Area2D::set_density); - ObjectTypeDB::bind_method(_MD("get_density"),&Area2D::get_density); + ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&Area2D::set_linear_damp); + ObjectTypeDB::bind_method(_MD("get_linear_damp"),&Area2D::get_linear_damp); + + ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&Area2D::set_angular_damp); + ObjectTypeDB::bind_method(_MD("get_angular_damp"),&Area2D::get_angular_damp); ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area2D::set_priority); ObjectTypeDB::bind_method(_MD("get_priority"),&Area2D::get_priority); @@ -290,6 +337,8 @@ void Area2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_enable_monitoring","enable"),&Area2D::set_enable_monitoring); ObjectTypeDB::bind_method(_MD("is_monitoring_enabled"),&Area2D::is_monitoring_enabled); + ObjectTypeDB::bind_method(_MD("get_overlapping_bodies"),&Area2D::get_overlapping_bodies); + ObjectTypeDB::bind_method(_MD("_body_inout"),&Area2D::_body_inout); @@ -302,7 +351,8 @@ void Area2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL,"gravity_point"),_SCS("set_gravity_is_point"),_SCS("is_gravity_a_point")); 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,"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_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")); @@ -314,7 +364,9 @@ Area2D::Area2D() : CollisionObject2D(Physics2DServer::get_singleton()->area_crea set_gravity(98);; set_gravity_vector(Vector2(0,1)); gravity_is_point=false; - density=0.1; + linear_damp=0.1; + angular_damp=1; + locked=false; priority=0; monitoring=false; set_enable_monitoring(true); diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h index b4c8edf138..f770e88a19 100644 --- a/scene/2d/area_2d.h +++ b/scene/2d/area_2d.h @@ -49,14 +49,16 @@ private: Vector2 gravity_vec; real_t gravity; bool gravity_is_point; - real_t density; + real_t linear_damp; + real_t angular_damp; int priority; bool monitoring; + bool locked; void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape); - void _body_enter_scene(ObjectID p_id); - void _body_exit_scene(ObjectID p_id); + void _body_enter_tree(ObjectID p_id); + void _body_exit_tree(ObjectID p_id); struct ShapePair { @@ -76,7 +78,7 @@ private: struct BodyState { int rc; - bool in_scene; + bool in_tree; VSet<ShapePair> shapes; }; @@ -103,8 +105,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_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_priority(real_t p_priority); real_t get_priority() const; @@ -112,6 +117,8 @@ public: void set_enable_monitoring(bool p_enable); bool is_monitoring_enabled() const; + Array get_overlapping_bodies() const; //function for script + Area2D(); ~Area2D(); diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp index fe6c9637e0..b3897010bf 100644 --- a/scene/2d/camera_2d.cpp +++ b/scene/2d/camera_2d.cpp @@ -33,10 +33,10 @@ void Camera2D::_update_scroll() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; - if (get_scene()->is_editor_hint()) { + if (get_tree()->is_editor_hint()) { update(); //will just be drawn return; } @@ -48,7 +48,7 @@ void Camera2D::_update_scroll() { if (viewport) { viewport->set_canvas_transform( xform ); } - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_camera_moved",xform); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,group_name,"_camera_moved",xform); }; } @@ -67,7 +67,7 @@ Vector2 Camera2D::get_zoom() const { Matrix32 Camera2D::get_camera_transform() { - if (!get_scene()) + if (!get_tree()) return Matrix32(); Size2 screen_size = get_viewport_rect().size; @@ -213,7 +213,7 @@ void Camera2D::_notification(int p_what) { _update_scroll(); } break; - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { viewport = NULL; Node *n=this; @@ -239,7 +239,7 @@ void Camera2D::_notification(int p_what) { } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (is_current()) { if (viewport) { @@ -316,10 +316,10 @@ bool Camera2D::is_current() const { void Camera2D::make_current() { - if (!is_inside_scene()) { + if (!is_inside_tree()) { current=true; } else { - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,group_name,"_make_current",this); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,group_name,"_make_current",this); } } diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp index d66f100b3f..ae857bbce9 100644 --- a/scene/2d/canvas_item.cpp +++ b/scene/2d/canvas_item.cpp @@ -38,7 +38,7 @@ bool CanvasItem::is_visible() const { - if (!is_inside_scene()) + if (!is_inside_tree()) return false; const CanvasItem *p=this; @@ -92,7 +92,7 @@ void CanvasItem::show() { hidden=false; VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,true); - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (is_visible()) { @@ -106,11 +106,11 @@ void CanvasItem::hide() { if (hidden) return; - bool propagate=is_inside_scene() && is_visible(); + bool propagate=is_inside_tree() && is_visible(); hidden=true; VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false); - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (propagate) _propagate_visibility_changed(false); @@ -147,7 +147,7 @@ void CanvasItem::_update_callback() { - if (!is_inside_scene()) { + if (!is_inside_tree()) { pending_update=false; return; } @@ -225,7 +225,7 @@ void CanvasItem::_sort_children() { pending_children_sort=false; - if (!is_inside_scene()) + if (!is_inside_tree()) return; for(int i=0;i<get_child_count();i++) { @@ -243,7 +243,7 @@ void CanvasItem::_sort_children() { void CanvasItem::_raise_self() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; VisualServer::get_singleton()->canvas_item_raise(canvas_item); @@ -283,7 +283,7 @@ void CanvasItem::_enter_canvas() { group = "root_canvas"+itos(canvas.get_id()); add_to_group(group); - get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self"); + get_tree()->call_group(SceneTree::GROUP_CALL_UNIQUE,group,"_raise_self"); } else { @@ -313,7 +313,7 @@ void CanvasItem::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { first_draw=true; pending_children_sort=false; @@ -324,14 +324,14 @@ void CanvasItem::_notification(int p_what) { } _enter_canvas(); if (!block_transform_notify && !xform_change.in_list()) { - get_scene()->xform_change_list.add(&xform_change); + get_tree()->xform_change_list.add(&xform_change); } } break; case NOTIFICATION_MOVED_IN_PARENT: { if (group!="") { - get_scene()->call_group(SceneMainLoop::GROUP_CALL_UNIQUE,group,"_raise_self"); + get_tree()->call_group(SceneTree::GROUP_CALL_UNIQUE,group,"_raise_self"); } else { CanvasItem *p = get_parent_item(); ERR_FAIL_COND(!p); @@ -340,9 +340,9 @@ void CanvasItem::_notification(int p_what) { } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (xform_change.in_list()) - get_scene()->xform_change_list.remove(&xform_change); + get_tree()->xform_change_list.remove(&xform_change); _exit_canvas(); if (C) { get_parent()->cast_to<CanvasItem>()->children_items.erase(C); @@ -379,7 +379,7 @@ bool CanvasItem::_is_visible_() const { void CanvasItem::update() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (pending_update) return; @@ -406,7 +406,7 @@ void CanvasItem::set_as_toplevel(bool p_toplevel) { if (toplevel==p_toplevel) return; - if (!is_inside_scene()) { + if (!is_inside_tree()) { toplevel=p_toplevel; return; } @@ -630,8 +630,8 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { if (!p_node->xform_change.in_list()) { if (!p_node->block_transform_notify) { - if (p_node->is_inside_scene()) - get_scene()->xform_change_list.add(&p_node->xform_change); + if (p_node->is_inside_tree()) + get_tree()->xform_change_list.add(&p_node->xform_change); } } @@ -648,13 +648,13 @@ void CanvasItem::_notify_transform(CanvasItem *p_node) { Rect2 CanvasItem::get_viewport_rect() const { - ERR_FAIL_COND_V(!is_inside_scene(),Rect2()); + ERR_FAIL_COND_V(!is_inside_tree(),Rect2()); return get_viewport()->get_visible_rect(); } RID CanvasItem::get_canvas() const { - ERR_FAIL_COND_V(!is_inside_scene(),RID()); + ERR_FAIL_COND_V(!is_inside_tree(),RID()); if (canvas_layer) return canvas_layer->get_world_2d()->get_canvas(); @@ -677,7 +677,7 @@ CanvasItem *CanvasItem::get_toplevel() const { Ref<World2D> CanvasItem::get_world_2d() const { - ERR_FAIL_COND_V(!is_inside_scene(),Ref<World2D>()); + ERR_FAIL_COND_V(!is_inside_tree(),Ref<World2D>()); CanvasItem *tl=get_toplevel(); @@ -693,7 +693,7 @@ Ref<World2D> CanvasItem::get_world_2d() const { RID CanvasItem::get_viewport_rid() const { - ERR_FAIL_COND_V(!is_inside_scene(),RID()); + ERR_FAIL_COND_V(!is_inside_tree(),RID()); return get_viewport()->get_viewport(); } @@ -720,6 +720,95 @@ bool CanvasItem::is_draw_behind_parent_enabled() const{ return behind; } +void CanvasItem::set_shader(const Ref<Shader>& p_shader) { + + ERR_FAIL_COND(p_shader.is_valid() && p_shader->get_mode()!=Shader::MODE_CANVAS_ITEM); + +#ifdef TOOLS_ENABLED + + if (shader.is_valid()) { + shader->disconnect("changed",this,"_shader_changed"); + } +#endif + shader=p_shader; + +#ifdef TOOLS_ENABLED + + if (shader.is_valid()) { + shader->connect("changed",this,"_shader_changed"); + } +#endif + + RID rid; + if (shader.is_valid()) + rid=shader->get_rid(); + VS::get_singleton()->canvas_item_set_shader(canvas_item,rid); + _change_notify(); //properties for shader exposed +} + +void CanvasItem::set_use_parent_shader(bool p_use_parent_shader) { + + use_parent_shader=p_use_parent_shader; + VS::get_singleton()->canvas_item_set_use_parent_shader(canvas_item,p_use_parent_shader); +} + +bool CanvasItem::get_use_parent_shader() const{ + + return use_parent_shader; +} + +Ref<Shader> CanvasItem::get_shader() const{ + + return shader; +} + +void CanvasItem::set_shader_param(const StringName& p_param,const Variant& p_value) { + + VS::get_singleton()->canvas_item_set_shader_param(canvas_item,p_param,p_value); +} + +Variant CanvasItem::get_shader_param(const StringName& p_param) const { + + return VS::get_singleton()->canvas_item_get_shader_param(canvas_item,p_param); +} + +bool CanvasItem::_set(const StringName& p_name, const Variant& p_value) { + + if (shader.is_valid()) { + StringName pr = shader->remap_param(p_name); + if (pr) { + set_shader_param(pr,p_value); + return true; + } + } + return false; +} + +bool CanvasItem::_get(const StringName& p_name,Variant &r_ret) const{ + + if (shader.is_valid()) { + StringName pr = shader->remap_param(p_name); + if (pr) { + r_ret=get_shader_param(pr); + return true; + } + } + return false; + +} +void CanvasItem::_get_property_list( List<PropertyInfo> *p_list) const{ + + if (shader.is_valid()) { + shader->get_param_list(p_list); + } +} + +#ifdef TOOLS_ENABLED +void CanvasItem::_shader_changed() { + + _change_notify(); +} +#endif void CanvasItem::_bind_methods() { @@ -761,7 +850,9 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("_set_on_top","on_top"),&CanvasItem::_set_on_top); ObjectTypeDB::bind_method(_MD("_is_on_top"),&CanvasItem::_is_on_top); - +#ifdef TOOLS_ENABLED + ObjectTypeDB::bind_method(_MD("_shader_changed"),&CanvasItem::_shader_changed); +#endif //ObjectTypeDB::bind_method(_MD("get_transform"),&CanvasItem::get_transform); ObjectTypeDB::bind_method(_MD("draw_line","from","to","color","width"),&CanvasItem::draw_line,DEFVAL(1.0)); @@ -786,15 +877,22 @@ void CanvasItem::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_world_2d"),&CanvasItem::get_world_2d); //ObjectTypeDB::bind_method(_MD("get_viewport"),&CanvasItem::get_viewport); + ObjectTypeDB::bind_method(_MD("set_shader","shader"),&CanvasItem::set_shader); + ObjectTypeDB::bind_method(_MD("get_shader"),&CanvasItem::get_shader); + ObjectTypeDB::bind_method(_MD("set_use_parent_shader","enable"),&CanvasItem::set_use_parent_shader); + ObjectTypeDB::bind_method(_MD("get_use_parent_shader"),&CanvasItem::get_use_parent_shader); + 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_PROPERTY( PropertyInfo(Variant::BOOL,"visibility/behind_parent"), _SCS("set_draw_behind_parent"),_SCS("is_draw_behind_parent_enabled") ); + 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::OBJECT,"shader/shader",PROPERTY_HINT_RESOURCE_TYPE, "CanvasItemShader,CanvasItemShaderGraph"), _SCS("set_shader"),_SCS("get_shader") ); + ADD_PROPERTYNZ( PropertyInfo(Variant::BOOL,"shader/use_parent"), _SCS("set_use_parent_shader"),_SCS("get_use_parent_shader") ); //exporting these two things doesn't really make much sense i think //ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), _SCS("set_as_toplevel"),_SCS("is_set_as_toplevel") ); //ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),_SCS("set_transform_notify"),_SCS("is_transform_notify_enabled")); @@ -824,7 +922,7 @@ void CanvasItem::_bind_methods() { Matrix32 CanvasItem::get_canvas_transform() const { - ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); + ERR_FAIL_COND_V(!is_inside_tree(),Matrix32()); if (canvas_layer) return canvas_layer->get_transform(); @@ -835,7 +933,7 @@ Matrix32 CanvasItem::get_canvas_transform() const { Matrix32 CanvasItem::get_viewport_transform() const { - ERR_FAIL_COND_V(!is_inside_scene(),Matrix32()); + ERR_FAIL_COND_V(!is_inside_tree(),Matrix32()); if (canvas_layer) { @@ -871,6 +969,7 @@ CanvasItem::CanvasItem() : xform_change(this) { block_transform_notify=false; // viewport=NULL; canvas_layer=NULL; + use_parent_shader; global_invalid=true; C=NULL; diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h index 604eef0527..ed3ade9df2 100644 --- a/scene/2d/canvas_item.h +++ b/scene/2d/canvas_item.h @@ -32,6 +32,7 @@ #include "scene/main/node.h" #include "scene/resources/texture.h" #include "scene/main/scene_main_loop.h" +#include "scene/resources/shader.h" class CanvasLayer; class Viewport; @@ -80,6 +81,9 @@ private: bool block_transform_notify; bool behind; + bool use_parent_shader; + Ref<Shader> shader; + mutable Matrix32 global_transform; mutable bool global_invalid; @@ -99,8 +103,9 @@ private: void _queue_sort_children(); void _sort_children(); - - +#ifdef TOOLS_ENABLED + void _shader_changed(); +#endif void _notify_transform(CanvasItem *p_node); void _set_on_top(bool p_on_top) { set_draw_behind_parent(!p_on_top); } @@ -108,9 +113,12 @@ private: 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; - _FORCE_INLINE_ void _notify_transform() { if (!is_inside_scene()) 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) notification(NOTIFICATION_LOCAL_TRANSFORM_CHANGED); } void item_rect_changed(); @@ -120,7 +128,7 @@ public: enum { - NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, //unique + NOTIFICATION_TRANSFORM_CHANGED=SceneTree::NOTIFICATION_TRANSFORM_CHANGED, //unique NOTIFICATION_DRAW=30, NOTIFICATION_VISIBILITY_CHANGED=31, NOTIFICATION_ENTER_CANVAS=32, @@ -204,7 +212,14 @@ public: RID get_canvas() const; Ref<World2D> get_world_2d() const; + void set_shader(const Ref<Shader>& p_shader); + Ref<Shader> get_shader() const; + + void set_use_parent_shader(bool p_use_parent_shader); + bool get_use_parent_shader() const; + void set_shader_param(const StringName& p_param,const Variant& p_value); + Variant get_shader_param(const StringName& p_param) const; CanvasItem(); ~CanvasItem(); diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp index e5d9872a28..3b859d9366 100644 --- a/scene/2d/collision_object_2d.cpp +++ b/scene/2d/collision_object_2d.cpp @@ -45,7 +45,7 @@ void CollisionObject2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (area) Physics2DServer::get_singleton()->area_set_transform(rid,get_global_transform()); @@ -69,7 +69,7 @@ void CollisionObject2D::_notification(int p_what) { Physics2DServer::get_singleton()->body_set_state(rid,Physics2DServer::BODY_STATE_TRANSFORM,get_global_transform()); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (area) { Physics2DServer::get_singleton()->area_set_space(rid,RID()); @@ -156,13 +156,13 @@ 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) ); + 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)+"/"; - p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_NOEDITOR) ); - p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); - p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape2D",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); } } diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp index ef63286697..1c0be60764 100644 --- a/scene/2d/collision_polygon_2d.cpp +++ b/scene/2d/collision_polygon_2d.cpp @@ -41,7 +41,6 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { bool solids=build_mode==BUILD_SOLIDS; - if (solids) { //here comes the sun, lalalala @@ -51,6 +50,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { Ref<ConvexPolygonShape2D> convex = memnew( ConvexPolygonShape2D ); convex->set_points(decomp[i]); co->add_shape(convex,get_transform()); + if (trigger) + co->set_shape_as_trigger(co->get_shape_count()-1,true); } @@ -71,6 +72,8 @@ void CollisionPolygon2D::_add_to_collision_object(Object *p_obj) { concave->set_segments(segments); co->add_shape(concave,get_transform()); + if (trigger) + co->set_shape_as_trigger(co->get_shape_count()-1,true); } @@ -95,7 +98,7 @@ void CollisionPolygon2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (!is_inside_scene()) + if (!is_inside_tree()) break; _update_parent(); @@ -166,6 +169,18 @@ Rect2 CollisionPolygon2D::get_item_rect() const { return aabb; } +void CollisionPolygon2D::set_trigger(bool p_trigger) { + + trigger=p_trigger; + _update_parent(); +} + +bool CollisionPolygon2D::is_trigger() const{ + + return trigger; +} + + void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("_add_to_collision_object"),&CollisionPolygon2D::_add_to_collision_object); @@ -175,14 +190,19 @@ void CollisionPolygon2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_build_mode"),&CollisionPolygon2D::set_build_mode); ObjectTypeDB::bind_method(_MD("get_build_mode"),&CollisionPolygon2D::get_build_mode); + ObjectTypeDB::bind_method(_MD("set_trigger"),&CollisionPolygon2D::set_trigger); + ObjectTypeDB::bind_method(_MD("is_trigger"),&CollisionPolygon2D::is_trigger); + 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::BOOL,"trigger"),_SCS("set_trigger"),_SCS("is_trigger")); } CollisionPolygon2D::CollisionPolygon2D() { aabb=Rect2(-10,-10,20,20); build_mode=BUILD_SOLIDS; + trigger=false; } diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h index 09c2060088..b8e27b6fb4 100644 --- a/scene/2d/collision_polygon_2d.h +++ b/scene/2d/collision_polygon_2d.h @@ -50,6 +50,7 @@ protected: Rect2 aabb; BuildMode build_mode; Vector<Point2> polygon; + bool trigger; void _add_to_collision_object(Object *p_obj); void _update_parent(); @@ -60,6 +61,9 @@ protected: static void _bind_methods(); public: + void set_trigger(bool p_trigger); + bool is_trigger() const; + void set_build_mode(BuildMode p_mode); BuildMode get_build_mode() const; diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp index 3f068f4ccc..9f35ade322 100644 --- a/scene/2d/collision_shape_2d.cpp +++ b/scene/2d/collision_shape_2d.cpp @@ -72,12 +72,12 @@ void CollisionShape2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { unparenting=false; } break; case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: { - if (!is_inside_scene()) + if (!is_inside_tree()) break; _update_parent(); diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp index 0e673ff791..e706ad658a 100644 --- a/scene/2d/joints_2d.cpp +++ b/scene/2d/joints_2d.cpp @@ -32,7 +32,7 @@ void Joint2D::_update_joint() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (joint.is_valid()) { @@ -86,7 +86,7 @@ void Joint2D::_notification(int p_what) { case NOTIFICATION_READY: { _update_joint(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { Physics2DServer::get_singleton()->free(joint); @@ -145,7 +145,7 @@ void PinJoint2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_DRAW: { - if (is_inside_scene() && get_scene()->is_editor_hint()) { + if (is_inside_tree() && get_tree()->is_editor_hint()) { draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3); draw_line(Point2(0,-10),Point2(0,+10),Color(0.7,0.6,0.0,0.5),3); @@ -197,7 +197,7 @@ void GrooveJoint2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_DRAW: { - if (is_inside_scene() && get_scene()->is_editor_hint()) { + if (is_inside_tree() && get_tree()->is_editor_hint()) { draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3); draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3); @@ -291,7 +291,7 @@ void DampedSpringJoint2D::_notification(int p_what) { switch(p_what) { case NOTIFICATION_DRAW: { - if (is_inside_scene() && get_scene()->is_editor_hint()) { + if (is_inside_tree() && get_tree()->is_editor_hint()) { draw_line(Point2(-10,0),Point2(+10,0),Color(0.7,0.6,0.0,0.5),3); draw_line(Point2(-10,length),Point2(+10,length),Color(0.7,0.6,0.0,0.5),3); diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp index 4c00db2429..8b4196ee7f 100644 --- a/scene/2d/node_2d.cpp +++ b/scene/2d/node_2d.cpp @@ -130,7 +130,7 @@ void Node2D::_update_transform() { VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat); - if (!is_inside_scene()) + if (!is_inside_tree()) return; @@ -272,7 +272,7 @@ void Node2D::set_transform(const Matrix32& p_transform) { VisualServer::get_singleton()->canvas_item_set_transform(get_canvas_item(),_mat); - if (!is_inside_scene()) + if (!is_inside_tree()) return; _notify_transform(); @@ -289,6 +289,35 @@ void Node2D::set_global_transform(const Matrix32& p_transform) { } +void Node2D::set_z(int p_z) { + + ERR_FAIL_COND(p_z<VS::CANVAS_ITEM_Z_MIN); + ERR_FAIL_COND(p_z>VS::CANVAS_ITEM_Z_MAX); + z=p_z; + VS::get_singleton()->canvas_item_set_z(get_canvas_item(),z); + +} + +void Node2D::set_z_as_relative(bool p_enabled) { + + if (z_relative==p_enabled) + return; + z_relative=p_enabled; + VS::get_singleton()->canvas_item_set_z_as_relative_to_parent(get_canvas_item(),p_enabled); +} + +bool Node2D::is_z_relative() const { + + return z_relative; +} + + +int Node2D::get_z() const{ + + return z; +} + + void Node2D::_bind_methods() { @@ -308,18 +337,25 @@ void Node2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("move_local_x","delta","scaled"),&Node2D::move_x,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("move_local_y","delta","scaled"),&Node2D::move_y,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("set_global_pos","pos"),&Node2D::set_global_pos); ObjectTypeDB::bind_method(_MD("get_global_pos"),&Node2D::get_global_pos); - ObjectTypeDB::bind_method(_MD("set_global_pos"),&Node2D::set_global_pos); ObjectTypeDB::bind_method(_MD("set_transform","xform"),&Node2D::set_transform); ObjectTypeDB::bind_method(_MD("set_global_transform","xform"),&Node2D::set_global_transform); + ObjectTypeDB::bind_method(_MD("set_z","z"),&Node2D::set_z); + ObjectTypeDB::bind_method(_MD("get_z"),&Node2D::get_z); + + ObjectTypeDB::bind_method(_MD("set_z_as_relative","enable"),&Node2D::set_z_as_relative); + ObjectTypeDB::bind_method(_MD("is_z_relative"),&Node2D::is_z_relative); + ObjectTypeDB::bind_method(_MD("edit_set_pivot"),&Node2D::edit_set_pivot); 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")); } @@ -331,6 +367,8 @@ Node2D::Node2D() { angle=0; scale=Vector2(1,1); _xform_dirty=false; + z=0; + z_relative=true; } diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index 582c56fa9b..61b8c829d6 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -38,6 +38,8 @@ class Node2D : public CanvasItem { Point2 pos; float angle; Size2 scale; + int z; + bool z_relative; Matrix32 _mat; @@ -85,6 +87,11 @@ public: void set_global_transform(const Matrix32& p_transform); void set_global_pos(const Point2& p_pos); + void set_z(int p_z); + int get_z() const; + + void set_z_as_relative(bool p_enabled); + bool is_z_relative() const; Matrix32 get_transform() const; diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp index 55607bd4eb..df37285f9d 100644 --- a/scene/2d/parallax_background.cpp +++ b/scene/2d/parallax_background.cpp @@ -36,13 +36,13 @@ void ParallaxBackground::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { group_name = "__cameras_"+itos(get_viewport().get_id()); add_to_group(group_name); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { remove_from_group(group_name); } break; @@ -78,7 +78,7 @@ void ParallaxBackground::set_scroll_offset(const Point2& p_ofs) { void ParallaxBackground::_update_scroll() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; Vector2 ofs = base_offset+offset*base_scale; diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp index 2cda51dccb..a0913ab50c 100644 --- a/scene/2d/parallax_layer.cpp +++ b/scene/2d/parallax_layer.cpp @@ -74,7 +74,7 @@ void ParallaxLayer::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { orig_offset=get_pos(); orig_scale=get_scale(); @@ -85,9 +85,9 @@ void ParallaxLayer::_notification(int p_what) { void ParallaxLayer::set_base_offset_and_scale(const Point2& p_offset,float p_scale) { - if (!is_inside_scene()) + if (!is_inside_tree()) return; - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) return; Point2 new_ofs = ((orig_offset+p_offset)*motion_scale)*p_scale; diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp index ded86702ef..6e2cf5954b 100644 --- a/scene/2d/particles_2d.cpp +++ b/scene/2d/particles_2d.cpp @@ -34,14 +34,14 @@ void ParticleAttractor2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { _update_owner(); } break; case NOTIFICATION_DRAW: { - if (!get_scene()->is_editor_hint()) + if (!get_tree()->is_editor_hint()) return; Vector2 pv; @@ -58,7 +58,7 @@ void ParticleAttractor2D::_notification(int p_what) { } } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (owner) { _set_owner(NULL); } @@ -76,7 +76,7 @@ void ParticleAttractor2D::_owner_exited() { void ParticleAttractor2D::_update_owner() { - if (!is_inside_scene() || !has_node(path)) { + if (!is_inside_tree() || !has_node(path)) { _set_owner(NULL); return; } @@ -98,7 +98,7 @@ void ParticleAttractor2D::_set_owner(Particles2D* p_owner) { return; if (owner) { - owner->disconnect("exit_scene",this,"_owner_exited"); + owner->disconnect("exit_tree",this,"_owner_exited"); owner->attractors.erase(this); owner=NULL; } @@ -106,7 +106,7 @@ void ParticleAttractor2D::_set_owner(Particles2D* p_owner) { if (owner) { - owner->connect("exit_scene",this,"_owner_exited",varray(),CONNECT_ONESHOT); + owner->connect("exit_tree",this,"_owner_exited",varray(),CONNECT_ONESHOT); owner->attractors.insert(this); } } @@ -355,6 +355,8 @@ void Particles2D::_process_particles(float p_delta) { p.rot=Math::deg2rad(param[PARAM_INITIAL_ANGLE]+param[PARAM_INITIAL_ANGLE]*randomness[PARAM_INITIAL_ANGLE]*_rand_from_seed(&rand_seed)); active_count++; + p.frame=Math::fmod(param[PARAM_ANIM_INITIAL_POS]+randomness[PARAM_ANIM_INITIAL_POS]*_rand_from_seed(&rand_seed),1.0); + } else { @@ -426,6 +428,8 @@ void Particles2D::_process_particles(float p_delta) { p.pos+=p.velocity*frame_time; p.rot+=Math::lerp(param[PARAM_SPIN_VELOCITY],param[PARAM_SPIN_VELOCITY]*randomness[PARAM_SPIN_VELOCITY]*_rand_from_seed(&rand_seed),randomness[PARAM_SPIN_VELOCITY])*frame_time; + float anim_spd=param[PARAM_ANIM_SPEED_SCALE]+param[PARAM_ANIM_SPEED_SCALE]*randomness[PARAM_ANIM_SPEED_SCALE]*_rand_from_seed(&rand_seed); + p.frame=Math::fposmod(p.frame+(frame_time/lifetime)*anim_spd,1.0); active_count++; @@ -457,7 +461,7 @@ void Particles2D::_notification(int p_what) { _process_particles( get_process_delta_time() ); } break; - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { float ppt=preprocess; while(ppt>0) { @@ -474,9 +478,13 @@ void Particles2D::_notification(int p_what) { RID ci=get_canvas_item(); Size2 size(1,1); Point2 center; + int total_frames=1; if (!texture.is_null()) { size=texture->get_size(); + size.x/=h_frames; + size.y/=v_frames; + total_frames=h_frames*v_frames; } @@ -507,7 +515,13 @@ void Particles2D::_notification(int p_what) { } - for(int i=0;i<particle_count;i++) { + int start_particle = (int)(time * (float)particle_count / lifetime); + + for (int id=0;id<particle_count;++id) { + int i = start_particle + id; + if (i >= particle_count) { + i -= particle_count; + } Particle &p=pdata[i]; if (!p.active) @@ -606,7 +620,17 @@ void Particles2D::_notification(int p_what) { if (texrid.is_valid()) { - texture->draw(ci,Point2(),color); + Rect2 src_rect; + src_rect.size=size; + + if (total_frames>1) { + int frame = Math::fast_ftoi(Math::floor(p.frame*total_frames)) % total_frames; + src_rect.pos.x = size.x * (frame%h_frames); + src_rect.pos.y = size.y * (frame/h_frames); + } + + + texture->draw_rect_region(ci,Rect2(Point2(),size),src_rect,color); //VisualServer::get_singleton()->canvas_item_add_texture_rect(ci,r,texrid,false,color); } else { VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2(),size),color); @@ -636,7 +660,9 @@ static const char* _particlesframe_property_names[Particles2D::PARAM_MAX]={ "params/initial_angle", "params/initial_size", "params/final_size", - "params/hue_variation" + "params/hue_variation", + "params/anim_speed_scale", + "params/anim_initial_pos", }; static const char* _particlesframe_property_rnames[Particles2D::PARAM_MAX]={ @@ -653,7 +679,9 @@ static const char* _particlesframe_property_rnames[Particles2D::PARAM_MAX]={ "randomness/initial_angle", "randomness/initial_size", "randomness/final_size", - "randomness/hue_variation" + "randomness/hue_variation", + "randomness/anim_speed_scale", + "randomness/anim_initial_pos", }; static const char* _particlesframe_property_ranges[Particles2D::PARAM_MAX]={ @@ -670,7 +698,9 @@ static const char* _particlesframe_property_ranges[Particles2D::PARAM_MAX]={ "0,360,0.01", "0,1024,0.01", "0,1024,0.01", - "0,1,0.01" + "0,1,0.01", + "0,128,0.01", + "0,1,0.01", }; @@ -903,6 +933,28 @@ bool Particles2D::is_flipped_v() const{ return flip_v; } +void Particles2D::set_h_frames(int p_frames) { + + ERR_FAIL_COND(p_frames<1); + h_frames=p_frames; +} + +int Particles2D::get_h_frames() const{ + + return h_frames; +} + +void Particles2D::set_v_frames(int p_frames){ + + ERR_FAIL_COND(p_frames<1); + v_frames=p_frames; +} +int Particles2D::get_v_frames() const{ + + return v_frames; +} + + void Particles2D::set_emission_points(const DVector<Vector2>& p_points) { @@ -952,6 +1004,12 @@ void Particles2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_flip_v","enable"),&Particles2D::set_flip_v); ObjectTypeDB::bind_method(_MD("is_flipped_v"),&Particles2D::is_flipped_v); + ObjectTypeDB::bind_method(_MD("set_h_frames","enable"),&Particles2D::set_h_frames); + ObjectTypeDB::bind_method(_MD("get_h_frames"),&Particles2D::get_h_frames); + + ObjectTypeDB::bind_method(_MD("set_v_frames","enable"),&Particles2D::set_v_frames); + ObjectTypeDB::bind_method(_MD("get_v_frames"),&Particles2D::get_v_frames); + ObjectTypeDB::bind_method(_MD("set_emission_half_extents","extents"),&Particles2D::set_emission_half_extents); ObjectTypeDB::bind_method(_MD("get_emission_half_extents"),&Particles2D::get_emission_half_extents); @@ -991,6 +1049,9 @@ void Particles2D::_bind_methods() { 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")); + for(int i=0;i<PARAM_MAX;i++) { @@ -1048,6 +1109,7 @@ Particles2D::Particles2D() { set_param(PARAM_INITIAL_ANGLE,0.0); set_param(PARAM_INITIAL_SIZE,1.0); set_param(PARAM_FINAL_SIZE,1.0); + set_param(PARAM_ANIM_SPEED_SCALE,1.0); time=0; @@ -1075,6 +1137,8 @@ Particles2D::Particles2D() { flip_h=false; flip_v=false; + v_frames=1; + h_frames=1; emit_timeout = 0; time_to_live = 0; diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h index 47bd078a7a..6d91fcafc3 100644 --- a/scene/2d/particles_2d.h +++ b/scene/2d/particles_2d.h @@ -99,6 +99,8 @@ public: PARAM_INITIAL_SIZE, PARAM_FINAL_SIZE, PARAM_HUE_VARIATION, + PARAM_ANIM_SPEED_SCALE, + PARAM_ANIM_INITIAL_POS, PARAM_MAX }; @@ -117,8 +119,9 @@ private: Point2 pos; Vector2 velocity; float rot; + float frame; uint32_t seed; - Particle() { active=false; seed=123465789; rot=0;} + Particle() { active=false; seed=123465789; rot=0; frame=0;} }; Vector<Particle> particles; @@ -146,6 +149,8 @@ private: float time_scale; bool flip_h; bool flip_v; + int h_frames; + int v_frames; Point2 emissor_offset; Vector2 initial_velocity; Vector2 extents; @@ -206,6 +211,13 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; + + void set_h_frames(int p_frames); + int get_h_frames() const; + + void set_v_frames(int p_frames); + int get_v_frames() const; + void set_color_phases(int p_phases); int get_color_phases() const; diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp index febec54124..5560274c98 100644 --- a/scene/2d/path_2d.cpp +++ b/scene/2d/path_2d.cpp @@ -31,7 +31,7 @@ void Path2D::_notification(int p_what) { - if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) { + if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_tree() && get_tree()->is_editor_hint()) { //draw the curve!! for(int i=0;i<curve->get_point_count();i++) { @@ -52,7 +52,7 @@ void Path2D::_notification(int p_what) { void Path2D::_curve_changed() { - if (is_inside_scene() && get_scene()->is_editor_hint()) + if (is_inside_tree() && get_tree()->is_editor_hint()) update(); } @@ -135,7 +135,7 @@ void PathFollow2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { Node *parent=get_parent(); if (parent) { @@ -147,7 +147,7 @@ void PathFollow2D::_notification(int p_what) { } } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { path=NULL; diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp index 78b5e23da0..6f18325212 100644 --- a/scene/2d/physics_body_2d.cpp +++ b/scene/2d/physics_body_2d.cpp @@ -43,13 +43,44 @@ void PhysicsBody2D::_notification(int p_what) { */ } +void PhysicsBody2D::set_one_way_collision_direction(const Vector2& p_dir) { + + one_way_collision_direction=p_dir; + Physics2DServer::get_singleton()->body_set_one_way_collision_direction(get_rid(),p_dir); +} + +Vector2 PhysicsBody2D::get_one_way_collision_direction() const{ + + return one_way_collision_direction; +} + + +void PhysicsBody2D::set_one_way_collision_max_depth(float p_depth) { + + one_way_collision_max_depth=p_depth; + Physics2DServer::get_singleton()->body_set_one_way_collision_max_depth(get_rid(),p_depth); + +} + +float PhysicsBody2D::get_one_way_collision_max_depth() const{ + + return one_way_collision_max_depth; +} + + void PhysicsBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody2D::set_layer_mask); ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody2D::get_layer_mask); + ObjectTypeDB::bind_method(_MD("set_one_way_collision_direction","dir"),&PhysicsBody2D::set_one_way_collision_direction); + ObjectTypeDB::bind_method(_MD("get_one_way_collision_direction"),&PhysicsBody2D::get_one_way_collision_direction); + ObjectTypeDB::bind_method(_MD("set_one_way_collision_max_depth","depth"),&PhysicsBody2D::set_one_way_collision_max_depth); + ObjectTypeDB::bind_method(_MD("get_one_way_collision_max_depth"),&PhysicsBody2D::get_one_way_collision_max_depth); ObjectTypeDB::bind_method(_MD("add_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::add_collision_exception_with); ObjectTypeDB::bind_method(_MD("remove_collision_exception_with","body:PhysicsBody2D"),&PhysicsBody2D::remove_collision_exception_with); ADD_PROPERTY(PropertyInfo(Variant::INT,"layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_layer_mask"),_SCS("get_layer_mask")); + ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2,"one_way_collision/direction"),_SCS("set_one_way_collision_direction"),_SCS("get_one_way_collision_direction")); + ADD_PROPERTYNZ(PropertyInfo(Variant::REAL,"one_way_collision/max_depth"),_SCS("set_one_way_collision_max_depth"),_SCS("get_one_way_collision_max_depth")); } void PhysicsBody2D::set_layer_mask(uint32_t p_mask) { @@ -66,6 +97,7 @@ uint32_t PhysicsBody2D::get_layer_mask() const { PhysicsBody2D::PhysicsBody2D(Physics2DServer::BodyMode p_mode) : CollisionObject2D( Physics2DServer::get_singleton()->body_create(p_mode), false) { mask=1; + set_one_way_collision_max_depth(0); } @@ -198,7 +230,7 @@ StaticBody2D::~StaticBody2D() { -void RigidBody2D::_body_enter_scene(ObjectID p_id) { +void RigidBody2D::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = obj ? obj->cast_to<Node>() : NULL; @@ -218,7 +250,7 @@ void RigidBody2D::_body_enter_scene(ObjectID p_id) { } -void RigidBody2D::_body_exit_scene(ObjectID p_id) { +void RigidBody2D::_body_exit_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = obj ? obj->cast_to<Node>() : NULL; @@ -250,18 +282,19 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap if (!E) { E = contact_monitor->body_map.insert(objid,BodyState()); - E->get().rc=0; - E->get().in_scene=node && node->is_inside_scene(); +// E->get().rc=0; + E->get().in_scene=node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid)); if (E->get().in_scene) { emit_signal(SceneStringNames::get_singleton()->body_enter,node); } } + //E->get().rc++; } - E->get().rc++; + if (node) E->get().shapes.insert(ShapePair(p_body_shape,p_local_shape)); @@ -272,24 +305,26 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap } else { - E->get().rc--; + //E->get().rc--; if (node) E->get().shapes.erase(ShapePair(p_body_shape,p_local_shape)); - if (E->get().rc==0) { + bool in_scene = E->get().in_scene; + + if (E->get().shapes.empty()) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); - node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); - if (E->get().in_scene) + 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); + if (in_scene) emit_signal(SceneStringNames::get_singleton()->body_exit,obj); } contact_monitor->body_map.erase(E); } - if (node && E->get().in_scene) { + if (node && in_scene) { emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_local_shape); } @@ -381,6 +416,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) { //process remotions + for(int i=0;i<toremove_count;i++) { _body_inout(0,toremove[i].body_id,toremove[i].pair.body_shape,toremove[i].pair.local_shape); @@ -388,6 +424,7 @@ void RigidBody2D::_direct_state_changed(Object *p_state) { //process aditions + for(int i=0;i<toadd_count;i++) { _body_inout(1,toadd[i].id,toadd[i].shape,toadd[i].local_shape); @@ -491,6 +528,42 @@ real_t RigidBody2D::get_bounce() const{ return bounce; } + +void RigidBody2D::set_gravity_scale(real_t p_gravity_scale){ + + gravity_scale=p_gravity_scale; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_GRAVITY_SCALE,gravity_scale); + +} +real_t RigidBody2D::get_gravity_scale() const{ + + return gravity_scale; +} + +void RigidBody2D::set_linear_damp(real_t p_linear_damp){ + + ERR_FAIL_COND(p_linear_damp<-1); + linear_damp=p_linear_damp; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_LINEAR_DAMP,linear_damp); + +} +real_t RigidBody2D::get_linear_damp() const{ + + return linear_damp; +} + +void RigidBody2D::set_angular_damp(real_t p_angular_damp){ + + ERR_FAIL_COND(p_angular_damp<-1); + angular_damp=p_angular_damp; + Physics2DServer::get_singleton()->body_set_param(get_rid(),Physics2DServer::BODY_PARAM_ANGULAR_DAMP,angular_damp); + +} +real_t RigidBody2D::get_angular_damp() const{ + + return angular_damp; +} + void RigidBody2D::set_axis_velocity(const Vector2& p_axis) { Vector2 v = state? state->get_linear_velocity() : linear_velocity; @@ -613,6 +686,26 @@ RigidBody2D::CCDMode RigidBody2D::get_continuous_collision_detection_mode() cons } +Array RigidBody2D::get_colliding_bodies() const { + + ERR_FAIL_COND_V(!contact_monitor,Array()); + + Array ret; + ret.resize(contact_monitor->body_map.size()); + int idx=0; + for (const Map<ObjectID,BodyState>::Element *E=contact_monitor->body_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; +} + void RigidBody2D::set_contact_monitor(bool p_enabled) { if (p_enabled==is_contact_monitor_enabled()) @@ -658,6 +751,15 @@ void RigidBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_bounce","bounce"),&RigidBody2D::set_bounce); ObjectTypeDB::bind_method(_MD("get_bounce"),&RigidBody2D::get_bounce); + ObjectTypeDB::bind_method(_MD("set_gravity_scale","gravity_scale"),&RigidBody2D::set_gravity_scale); + ObjectTypeDB::bind_method(_MD("get_gravity_scale"),&RigidBody2D::get_gravity_scale); + + ObjectTypeDB::bind_method(_MD("set_linear_damp","linear_damp"),&RigidBody2D::set_linear_damp); + ObjectTypeDB::bind_method(_MD("get_linear_damp"),&RigidBody2D::get_linear_damp); + + ObjectTypeDB::bind_method(_MD("set_angular_damp","angular_damp"),&RigidBody2D::set_angular_damp); + ObjectTypeDB::bind_method(_MD("get_angular_damp"),&RigidBody2D::get_angular_damp); + ObjectTypeDB::bind_method(_MD("set_linear_velocity","linear_velocity"),&RigidBody2D::set_linear_velocity); ObjectTypeDB::bind_method(_MD("get_linear_velocity"),&RigidBody2D::get_linear_velocity); @@ -689,8 +791,10 @@ void RigidBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody2D::is_able_to_sleep); ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody2D::_direct_state_changed); - ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody2D::_body_enter_scene); - ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody2D::_body_exit_scene); + ObjectTypeDB::bind_method(_MD("_body_enter_tree"),&RigidBody2D::_body_enter_tree); + ObjectTypeDB::bind_method(_MD("_body_exit_tree"),&RigidBody2D::_body_exit_tree); + + ObjectTypeDB::bind_method(_MD("get_colliding_bodies"),&RigidBody2D::get_colliding_bodies); BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:Physics2DDirectBodyState"))); @@ -699,6 +803,7 @@ void RigidBody2D::_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::INT,"continuous_cd",PROPERTY_HINT_ENUM,"Disabled,Cast Ray,Cast Shape"),_SCS("set_continuous_collision_detection_mode"),_SCS("get_continuous_collision_detection_mode")); ADD_PROPERTY( PropertyInfo(Variant::INT,"contacts_reported"),_SCS("set_max_contacts_reported"),_SCS("get_max_contacts_reported")); @@ -707,6 +812,8 @@ void RigidBody2D::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::BOOL,"can_sleep"),_SCS("set_can_sleep"),_SCS("is_able_to_sleep")); ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"velocity/linear"),_SCS("set_linear_velocity"),_SCS("get_linear_velocity")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"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"))); @@ -731,6 +838,11 @@ RigidBody2D::RigidBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_RIGID) { bounce=0; mass=1; friction=1; + + gravity_scale=1; + linear_damp=-1; + angular_damp=-1; + max_contacts_reported=0; state=NULL; @@ -798,7 +910,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { colliding=false; - ERR_FAIL_COND_V(!is_inside_scene(),Vector2()); + ERR_FAIL_COND_V(!is_inside_tree(),Vector2()); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); ERR_FAIL_COND_V(!dss,Vector2()); const int max_shapes=32; @@ -831,7 +943,8 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { //motion recover for(int i=0;i<get_shape_count();i++) { - + if (is_shape_set_as_trigger(i)) + continue; if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),Vector2(),margin,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) collided=true; @@ -851,7 +964,7 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { //if (d<margin) /// continue; - recover_motion+=(b-a)*0.2; + recover_motion+=(b-a)*0.4; } if (recover_motion==Vector2()) { @@ -875,11 +988,14 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; float lsafe,lunsafe; bool valid = dss->cast_motion(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i), p_motion, 0,lsafe,lunsafe,exclude,get_layer_mask(),mask); //print_line("shape: "+itos(i)+" travel:"+rtos(ltravel)); if (!valid) { + safe=0; unsafe=0; best_shape=i; //sadly it's the best @@ -911,15 +1027,19 @@ Vector2 KinematicBody2D::move(const Vector2& p_motion) { bool c2 = dss->rest_info(get_shape(best_shape)->get_rid(), ugt*get_shape_transform(best_shape), Vector2(), margin,&rest_info,exclude,get_layer_mask(),mask); if (!c2) { //should not happen, but floating point precision is so weird.. + colliding=false; } else { + //print_line("Travel: "+rtos(travel)); colliding=true; collision=rest_info.point; normal=rest_info.normal; collider=rest_info.collider_id; collider_vel=rest_info.linear_velocity; + collider_shape=rest_info.shape; + collider_metadata=rest_info.metadata; } } @@ -940,7 +1060,7 @@ Vector2 KinematicBody2D::move_to(const Vector2& p_position) { bool KinematicBody2D::can_move_to(const Vector2& p_position, bool p_discrete) { - ERR_FAIL_COND_V(!is_inside_scene(),false); + ERR_FAIL_COND_V(!is_inside_tree(),false); Physics2DDirectSpaceState *dss = Physics2DServer::get_singleton()->space_get_direct_state(get_world_2d()->get_space()); ERR_FAIL_COND_V(!dss,false); @@ -980,7 +1100,7 @@ bool KinematicBody2D::can_move_to(const Vector2& p_position, bool p_discrete) { bool KinematicBody2D::is_colliding() const { - ERR_FAIL_COND_V(!is_inside_scene(),false); + ERR_FAIL_COND_V(!is_inside_tree(),false); return colliding; } @@ -1008,6 +1128,20 @@ ObjectID KinematicBody2D::get_collider() const { return collider; } + +int KinematicBody2D::get_collider_shape() const { + + ERR_FAIL_COND_V(!colliding,0); + return collider_shape; +} + +Variant KinematicBody2D::get_collider_metadata() const { + + ERR_FAIL_COND_V(!colliding,0); + return collider_metadata; + +} + void KinematicBody2D::set_collide_with_static_bodies(bool p_enable) { collide_static=p_enable; @@ -1071,6 +1205,8 @@ void KinematicBody2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody2D::get_collision_normal); ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody2D::get_collider_velocity); ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody2D::_get_collider); + ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody2D::get_collider_shape); + ObjectTypeDB::bind_method(_MD("get_collider_metadata"),&KinematicBody2D::get_collider_metadata); ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody2D::set_collide_with_static_bodies); @@ -1107,6 +1243,8 @@ KinematicBody2D::KinematicBody2D() : PhysicsBody2D(Physics2DServer::BODY_MODE_KI colliding=false; collider=0; + collider_shape=0; + margin=0.08; } KinematicBody2D::~KinematicBody2D() { diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h index 7e3fd978a0..eed43c95be 100644 --- a/scene/2d/physics_body_2d.h +++ b/scene/2d/physics_body_2d.h @@ -39,6 +39,8 @@ class PhysicsBody2D : public CollisionObject2D { OBJ_TYPE(PhysicsBody2D,CollisionObject2D); uint32_t mask; + Vector2 one_way_collision_direction; + float one_way_collision_max_depth; protected: void _notification(int p_what); @@ -53,6 +55,12 @@ public: void add_collision_exception_with(Node* p_node); //must be physicsbody void remove_collision_exception_with(Node* p_node); + void set_one_way_collision_direction(const Vector2& p_dir); + Vector2 get_one_way_collision_direction() const; + + void set_one_way_collision_max_depth(float p_dir); + float get_one_way_collision_max_depth() const; + PhysicsBody2D(); }; @@ -119,6 +127,9 @@ private: real_t bounce; real_t mass; real_t friction; + real_t gravity_scale; + real_t linear_damp; + real_t angular_damp; Vector2 linear_velocity; real_t angular_velocity; @@ -156,7 +167,7 @@ private: }; struct BodyState { - int rc; + //int rc; bool in_scene; VSet<ShapePair> shapes; }; @@ -170,8 +181,8 @@ private: ContactMonitor *contact_monitor; - void _body_enter_scene(ObjectID p_id); - void _body_exit_scene(ObjectID p_id); + void _body_enter_tree(ObjectID p_id); + void _body_exit_tree(ObjectID p_id); void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape); @@ -198,6 +209,15 @@ public: void set_bounce(real_t p_bounce); real_t get_bounce() 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_linear_velocity(const Vector2& p_velocity); Vector2 get_linear_velocity() const; @@ -229,6 +249,8 @@ public: void set_applied_force(const Vector2& p_force); Vector2 get_applied_force() const; + Array get_colliding_bodies() const; //function for script + RigidBody2D(); ~RigidBody2D(); @@ -254,7 +276,8 @@ class KinematicBody2D : public PhysicsBody2D { Vector2 normal; Vector2 collider_vel; ObjectID collider; - + int collider_shape; + Variant collider_metadata; Variant _get_collider() const; @@ -273,6 +296,8 @@ public: Vector2 get_collision_normal() const; Vector2 get_collider_velocity() const; ObjectID get_collider() const; + int get_collider_shape() const; + Variant get_collider_metadata() const; void set_collide_with_static_bodies(bool p_enable); bool can_collide_with_static_bodies() const; diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp index 2b4be734af..217a98aaea 100644 --- a/scene/2d/polygon_2d.cpp +++ b/scene/2d/polygon_2d.cpp @@ -359,5 +359,6 @@ Polygon2D::Polygon2D() { tex_rot=0; tex_tile=true; tex_scale=Vector2(1,1); + color=Color(1,1,1); rect_cache_dirty=true; } diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp index ca3be9aa8f..2db2be123b 100644 --- a/scene/2d/position_2d.cpp +++ b/scene/2d/position_2d.cpp @@ -45,14 +45,14 @@ void Position2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { update(); } break; case NOTIFICATION_DRAW: { - if (!is_inside_scene()) + if (!is_inside_tree()) break; - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) _draw_cross(); } break; diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp index 8479338521..e352ac64f5 100644 --- a/scene/2d/ray_cast_2d.cpp +++ b/scene/2d/ray_cast_2d.cpp @@ -33,7 +33,7 @@ void RayCast2D::set_cast_to(const Vector2& p_point) { cast_to=p_point; - if (is_inside_scene() && get_scene()->is_editor_hint()) + if (is_inside_tree() && get_tree()->is_editor_hint()) update(); } @@ -82,7 +82,7 @@ Vector2 RayCast2D::get_collision_normal() const{ void RayCast2D::set_enabled(bool p_enabled) { enabled=p_enabled; - if (is_inside_scene() && !get_scene()->is_editor_hint()) + if (is_inside_tree() && !get_tree()->is_editor_hint()) set_fixed_process(p_enabled); if (!p_enabled) collided=false; @@ -101,15 +101,15 @@ void RayCast2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { - if (enabled && !get_scene()->is_editor_hint()) + if (enabled && !get_tree()->is_editor_hint()) set_fixed_process(true); else set_fixed_process(false); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (enabled) set_fixed_process(false); @@ -118,7 +118,7 @@ void RayCast2D::_notification(int p_what) { #ifdef TOOLS_ENABLED case NOTIFICATION_DRAW: { - if (!get_scene()->is_editor_hint()) + if (!get_tree()->is_editor_hint()) break; Matrix32 xf; xf.rotate(cast_to.atan2()); diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp index 80d038f6f8..b170986017 100644 --- a/scene/2d/remote_transform_2d.cpp +++ b/scene/2d/remote_transform_2d.cpp @@ -45,7 +45,7 @@ void RemoteTransform2D::_update_cache() { void RemoteTransform2D::_update_remote() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (!cache) @@ -59,7 +59,7 @@ void RemoteTransform2D::_update_remote() { if (!n) return; - if (!n->is_inside_scene()) + if (!n->is_inside_tree()) return; //todo make faster @@ -77,7 +77,7 @@ void RemoteTransform2D::_notification(int p_what) { } break; case NOTIFICATION_TRANSFORM_CHANGED: { - if (!is_inside_scene()) + if (!is_inside_tree()) break; if (cache) { @@ -95,7 +95,7 @@ void RemoteTransform2D::_notification(int p_what) { void RemoteTransform2D::set_remote_node(const NodePath& p_remote_node) { remote_node=p_remote_node; - if (is_inside_scene()) + if (is_inside_tree()) _update_cache(); } diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h index 9561e72255..05a9b20f6e 100644 --- a/scene/2d/remote_transform_2d.h +++ b/scene/2d/remote_transform_2d.h @@ -38,7 +38,7 @@ class RemoteTransform2D : public Node2D { void _update_remote(); void _update_cache(); - void _node_exited_scene(); + //void _node_exited_scene(); protected: static void _bind_methods(); diff --git a/scene/2d/sample_player_2d.cpp b/scene/2d/sample_player_2d.cpp index bc1734ec06..a231acd13d 100644 --- a/scene/2d/sample_player_2d.cpp +++ b/scene/2d/sample_player_2d.cpp @@ -89,7 +89,7 @@ void SamplePlayer2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { SpatialSound2DServer::get_singleton()->source_set_polyphony(get_source_rid(),polyphony); @@ -102,6 +102,7 @@ void SamplePlayer2D::_notification(int p_what) { void SamplePlayer2D::set_sample_library(const Ref<SampleLibrary>& p_library) { library=p_library; + _change_notify(); } Ref<SampleLibrary> SamplePlayer2D::get_sample_library() const { diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp index b606634819..2ac3c06031 100644 --- a/scene/2d/screen_button.cpp +++ b/scene/2d/screen_button.cpp @@ -69,9 +69,9 @@ void TouchScreenButton::_notification(int p_what) { case NOTIFICATION_DRAW: { - if (!is_inside_scene()) + if (!is_inside_tree()) return; - if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY) + if (!get_tree()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY) return; if (finger_pressed!=-1) { @@ -87,13 +87,13 @@ void TouchScreenButton::_notification(int p_what) { } } break; - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { - if (!get_scene()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY) + if (!get_tree()->is_editor_hint() && !OS::get_singleton()->has_touchscreen_ui_hint() && visibility==VISIBILITY_TOUCHSCREEN_ONLY) return; update(); - if (!get_scene()->is_editor_hint()) + if (!get_tree()->is_editor_hint()) set_process_input(true); if (action.operator String()!="" && InputMap::get_singleton()->has_action(action)) { @@ -129,7 +129,7 @@ String TouchScreenButton::get_action() const { void TouchScreenButton::_input(const InputEvent& p_event) { - if (!get_scene()) + if (!get_tree()) return; if (p_event.device != 0) @@ -149,7 +149,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { ie.ID=0; ie.action.action=action_id; ie.action.pressed=false; - get_scene()->input_event(ie); + get_tree()->input_event(ie); } finger_pressed=-1; @@ -193,7 +193,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { ie.ID=0; ie.action.action=action_id; ie.action.pressed=true; - get_scene()->input_event(ie); + get_tree()->input_event(ie); } update(); @@ -213,7 +213,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { ie.ID=0; ie.action.action=action_id; ie.action.pressed=false; - get_scene()->input_event(ie); + get_tree()->input_event(ie); } finger_pressed=-1; @@ -268,7 +268,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { ie.ID=0; ie.action.action=action_id; ie.action.pressed=true; - get_scene()->input_event(ie); + get_tree()->input_event(ie); } update(); @@ -289,7 +289,7 @@ void TouchScreenButton::_input(const InputEvent& p_event) { ie.ID=0; ie.action.action=action_id; ie.action.pressed=false; - get_scene()->input_event(ie); + get_tree()->input_event(ie); } finger_pressed=-1; update(); diff --git a/scene/2d/sound_player_2d.cpp b/scene/2d/sound_player_2d.cpp index 2fffef4e51..ef51295476 100644 --- a/scene/2d/sound_player_2d.cpp +++ b/scene/2d/sound_player_2d.cpp @@ -39,7 +39,7 @@ void SoundPlayer2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { //find the sound space source_rid = SpatialSound2DServer::get_singleton()->source_create(get_world_2d()->get_sound_space()); @@ -56,7 +56,7 @@ void SoundPlayer2D::_notification(int p_what) { SpatialSound2DServer::get_singleton()->source_set_transform(source_rid,get_global_transform()); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (source_rid.is_valid()) SpatialSound2DServer::get_singleton()->free(source_rid); diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp index 7d033ed87f..82f5a6972a 100644 --- a/scene/2d/sprite.cpp +++ b/scene/2d/sprite.cpp @@ -34,6 +34,7 @@ void Sprite::edit_set_pivot(const Point2& p_pivot) { set_offset(p_pivot); + } Point2 Sprite::edit_get_pivot() const { @@ -64,20 +65,20 @@ void Sprite::_notification(int p_what) { break; */ - Size2i s; - Rect2i src_rect; + Size2 s; + Rect2 src_rect; if (region) { s=region_rect.size; src_rect=region_rect; } else { - s = texture->get_size(); - s=s/Size2i(hframes,vframes); + s = Size2(texture->get_size()); + s=s/Size2(hframes,vframes); src_rect.size=s; - src_rect.pos.x+=(frame%hframes)*s.x; - src_rect.pos.y+=(frame/hframes)*s.y; + src_rect.pos.x+=float(frame%hframes)*s.x; + src_rect.pos.y+=float(frame/hframes)*s.y; } @@ -85,7 +86,7 @@ void Sprite::_notification(int p_what) { if (centered) ofs-=s/2; - Rect2i dst_rect(ofs,s); + Rect2 dst_rect(ofs,s); if (hflip) dst_rect.size.x=-dst_rect.size.x; @@ -136,6 +137,7 @@ void Sprite::set_offset(const Point2& p_offset) { offset=p_offset; update(); item_rect_changed(); + _change_notify("offset"); } Point2 Sprite::get_offset() const { @@ -199,6 +201,8 @@ void Sprite::set_frame(int p_frame) { item_rect_changed(); frame=p_frame; + + emit_signal(SceneStringNames::get_singleton()->frame_changed); } int Sprite::get_frame() const { @@ -307,6 +311,8 @@ void Sprite::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_modulate","modulate"),&Sprite::set_modulate); ObjectTypeDB::bind_method(_MD("get_modulate"),&Sprite::get_modulate); + 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")); @@ -365,7 +371,7 @@ void ViewportSprite::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (!viewport_path.is_empty()) { @@ -380,7 +386,7 @@ void ViewportSprite::_notification(int p_what) { item_rect_changed(); } } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (texture.is_valid()) { @@ -422,7 +428,7 @@ void ViewportSprite::set_viewport_path(const NodePath& p_viewport) { viewport_path=p_viewport; update(); - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (texture.is_valid()) { diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 6403454588..9fcf34cee6 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -33,7 +33,7 @@ void TileMap::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { pending_update=true; _update_dirty_quadrants(); @@ -43,7 +43,7 @@ void TileMap::_notification(int p_what) { } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { _update_quadrant_space(RID()); @@ -68,7 +68,7 @@ void TileMap::_update_quadrant_space(const RID& p_space) { void TileMap::_update_quadrant_transform() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; Matrix32 global_transform = get_global_transform(); @@ -106,9 +106,9 @@ Ref<TileSet> TileMap::get_tileset() const { return tile_set; } -void TileMap::set_cell_size(int p_size) { +void TileMap::set_cell_size(Size2 p_size) { - ERR_FAIL_COND(p_size<1); + ERR_FAIL_COND(p_size.x<1 || p_size.y<1); _clear_quadrants(); cell_size=p_size; @@ -117,7 +117,7 @@ void TileMap::set_cell_size(int p_size) { } -int TileMap::get_cell_size() const { +Size2 TileMap::get_cell_size() const { return cell_size; } @@ -164,13 +164,14 @@ void TileMap::_update_dirty_quadrants() { if (!pending_update) return; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (!tile_set.is_valid()) return; VisualServer *vs = VisualServer::get_singleton(); Physics2DServer *ps = Physics2DServer::get_singleton(); + Vector2 tofs = get_cell_draw_offset(); while (dirty_quadrant_list.first()) { @@ -178,6 +179,7 @@ void TileMap::_update_dirty_quadrants() { vs->canvas_item_clear(q.canvas_item); ps->body_clear_shapes(q.static_body); + int shape_idx=0; for(int i=0;i<q.cells.size();i++) { @@ -189,7 +191,7 @@ void TileMap::_update_dirty_quadrants() { Ref<Texture> tex = tile_set->tile_get_texture(c.id); Vector2 tile_ofs = tile_set->tile_get_texture_offset(c.id); - Vector2 offset = Point2( E->key().x, E->key().y )*cell_size - q.pos; + Vector2 offset = _map_to_world(E->key().x, E->key().y) - q.pos + tofs; if (!tex.is_valid()) continue; @@ -258,6 +260,8 @@ void TileMap::_update_dirty_quadrants() { ps->body_add_shape(q.static_body,shape->get_rid(),xform); + ps->body_set_shape_metadata(q.static_body,shape_idx++,Vector2(E->key().x,E->key().y)); + } } } @@ -299,17 +303,22 @@ void TileMap::_recompute_rect_cache() { for (Map<PosKey,Quadrant>::Element *E=quadrant_map.front();E;E=E->next()) { - Rect2 r( Point2(E->key().x, E->key().y)*cell_size*quadrant_size, Size2(1,1)*cell_size*quadrant_size ); + Rect2 r; + r.pos=_map_to_world(E->key().x*quadrant_size, E->key().y*quadrant_size); + r.expand_to( _map_to_world(E->key().x*quadrant_size+quadrant_size, E->key().y*quadrant_size) ); + r.expand_to( _map_to_world(E->key().x*quadrant_size+quadrant_size, E->key().y*quadrant_size+quadrant_size) ); + r.expand_to( _map_to_world(E->key().x*quadrant_size, E->key().y*quadrant_size+quadrant_size) ); if (E==quadrant_map.front()) r_total=r; else r_total=r_total.merge(r); } + if (r_total==Rect2()) { rect_cache=Rect2(-10,-10,20,20); } else { - rect_cache=r_total; + rect_cache=r_total.grow(MAX(cell_size.x,cell_size.y)*quadrant_size); } item_rect_changed(); @@ -323,8 +332,10 @@ void TileMap::_recompute_rect_cache() { Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const PosKey& p_qk) { Matrix32 xform; - xform.set_origin(Point2(p_qk.x,p_qk.y)*quadrant_size*cell_size); + //xform.set_origin(Point2(p_qk.x,p_qk.y)*cell_size*quadrant_size); Quadrant q; + q.pos = _map_to_world(p_qk.x*quadrant_size,p_qk.y*quadrant_size); + xform.set_origin( q.pos ); q.canvas_item = VisualServer::get_singleton()->canvas_item_create(); VisualServer::get_singleton()->canvas_item_set_parent( q.canvas_item, get_canvas_item() ); VisualServer::get_singleton()->canvas_item_set_transform( q.canvas_item, xform ); @@ -334,14 +345,13 @@ Map<TileMap::PosKey,TileMap::Quadrant>::Element *TileMap::_create_quadrant(const Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_FRICTION,friction); Physics2DServer::get_singleton()->body_set_param(q.static_body,Physics2DServer::BODY_PARAM_BOUNCE,bounce); - if (is_inside_scene()) { + if (is_inside_tree()) { xform = get_global_transform() * xform; RID space = get_world_2d()->get_space(); Physics2DServer::get_singleton()->body_set_space(q.static_body,space); } Physics2DServer::get_singleton()->body_set_state(q.static_body,Physics2DServer::BODY_STATE_TRANSFORM,xform); - q.pos=Vector2(p_qk.x,p_qk.y)*quadrant_size*cell_size; rect_cache_dirty=true; quadrant_order_dirty=true; @@ -369,7 +379,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey,Quadrant>::Element *Q) { if (pending_update) return; pending_update=true; - if (!is_inside_scene()) + if (!is_inside_tree()) return; call_deferred("_update_dirty_quadrants"); } @@ -478,8 +488,11 @@ void TileMap::_recreate_quadrants() { } Q->get().cells.insert(E->key()); - + _make_quadrant_dirty(Q); } + + + } void TileMap::_clear_quadrants() { @@ -614,6 +627,152 @@ uint32_t TileMap::get_collision_layer_mask() const { return collision_layer; } +void TileMap::set_mode(Mode p_mode) { + + _clear_quadrants(); + mode=p_mode; + _recreate_quadrants(); + emit_signal("settings_changed"); +} + +TileMap::Mode TileMap::get_mode() const { + return mode; +} + +void TileMap::set_half_offset(HalfOffset p_half_offset) { + + _clear_quadrants(); + half_offset=p_half_offset; + _recreate_quadrants(); + emit_signal("settings_changed"); +} + +Vector2 TileMap::get_cell_draw_offset() const { + + switch(mode) { + + case MODE_SQUARE: { + + return Vector2(); + } break; + case MODE_ISOMETRIC: { + + return Vector2(-cell_size.x*0.5,0); + + } break; + case MODE_CUSTOM: { + + Vector2 min; + min.x = MIN(custom_transform[0].x,min.x); + min.y = MIN(custom_transform[0].y,min.y); + min.x = MIN(custom_transform[1].x,min.x); + min.y = MIN(custom_transform[1].y,min.y); + return min; + } break; + } + + return Vector2(); + +} + +TileMap::HalfOffset TileMap::get_half_offset() const { + return half_offset; +} + +Matrix32 TileMap::get_cell_transform() const { + + switch(mode) { + + case MODE_SQUARE: { + + Matrix32 m; + m[0]*=cell_size.x; + m[1]*=cell_size.y; + return m; + } break; + case MODE_ISOMETRIC: { + + //isometric only makes sense when y is positive in both x and y vectors, otherwise + //the drawing of tiles will overlap + Matrix32 m; + m[0]=Vector2(cell_size.x*0.5,cell_size.y*0.5); + m[1]=Vector2(-cell_size.x*0.5,cell_size.y*0.5); + return m; + + } break; + case MODE_CUSTOM: { + + return custom_transform; + } break; + } + + return Matrix32(); +} + +void TileMap::set_custom_transform(const Matrix32& p_xform) { + + _clear_quadrants(); + custom_transform=p_xform; + _recreate_quadrants(); + emit_signal("settings_changed"); + +} + +Matrix32 TileMap::get_custom_transform() const{ + + return custom_transform; +} + +Vector2 TileMap::_map_to_world(int x,int y,bool p_ignore_ofs) const { + + Vector2 ret = get_cell_transform().xform(Vector2(x,y)); + if (!p_ignore_ofs) { + switch(half_offset) { + + case HALF_OFFSET_X: { + if (ABS(y)&1) { + + ret+=get_cell_transform()[0]*0.5; + } + } break; + case HALF_OFFSET_Y: { + if (ABS(x)&1) { + ret+=get_cell_transform()[1]*0.5; + } + } break; + default: {} + } + } + return ret; +} +Vector2 TileMap::map_to_world(const Vector2& p_pos,bool p_ignore_ofs) const { + + return _map_to_world(p_pos.x,p_pos.y,p_ignore_ofs); +} +Vector2 TileMap::world_to_map(const Vector2& p_pos) const{ + + Vector2 ret = get_cell_transform().affine_inverse().xform(p_pos); + + + switch(half_offset) { + + case HALF_OFFSET_X: { + if (int(ret.y)&1) { + + ret.x-=0.5; + } + } break; + case HALF_OFFSET_Y: { + if (int(ret.x)&1) { + ret.y-=0.5; + } + } break; + default: {} + } + + return ret.floor(); +} + void TileMap::_bind_methods() { @@ -621,10 +780,21 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_tileset","tileset:TileSet"),&TileMap::set_tileset); ObjectTypeDB::bind_method(_MD("get_tileset:TileSet"),&TileMap::get_tileset); + ObjectTypeDB::bind_method(_MD("set_mode","mode"),&TileMap::set_mode); + ObjectTypeDB::bind_method(_MD("get_mode"),&TileMap::get_mode); + + ObjectTypeDB::bind_method(_MD("set_half_offset","half_offset"),&TileMap::set_half_offset); + ObjectTypeDB::bind_method(_MD("get_half_offset"),&TileMap::get_half_offset); + + ObjectTypeDB::bind_method(_MD("set_custom_transform","custom_transform"),&TileMap::set_custom_transform); + ObjectTypeDB::bind_method(_MD("get_custom_transform"),&TileMap::get_custom_transform); ObjectTypeDB::bind_method(_MD("set_cell_size","size"),&TileMap::set_cell_size); ObjectTypeDB::bind_method(_MD("get_cell_size"),&TileMap::get_cell_size); + ObjectTypeDB::bind_method(_MD("_set_old_cell_size","size"),&TileMap::_set_old_cell_size); + ObjectTypeDB::bind_method(_MD("_get_old_cell_size"),&TileMap::_get_old_cell_size); + ObjectTypeDB::bind_method(_MD("set_quadrant_size","size"),&TileMap::set_quadrant_size); ObjectTypeDB::bind_method(_MD("get_quadrant_size"),&TileMap::get_quadrant_size); @@ -650,6 +820,9 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("clear"),&TileMap::clear); + ObjectTypeDB::bind_method(_MD("map_to_world","mappos","ignore_half_ofs"),&TileMap::map_to_world,DEFVAL(false)); + ObjectTypeDB::bind_method(_MD("world_to_map","worldpos"),&TileMap::world_to_map); + ObjectTypeDB::bind_method(_MD("_clear_quadrants"),&TileMap::_clear_quadrants); ObjectTypeDB::bind_method(_MD("_recreate_quadrants"),&TileMap::_recreate_quadrants); ObjectTypeDB::bind_method(_MD("_update_dirty_quadrants"),&TileMap::_update_dirty_quadrants); @@ -657,17 +830,28 @@ void TileMap::_bind_methods() { ObjectTypeDB::bind_method(_MD("_set_tile_data"),&TileMap::_set_tile_data); ObjectTypeDB::bind_method(_MD("_get_tile_data"),&TileMap::_get_tile_data); - ADD_PROPERTY( PropertyInfo(Variant::INT,"cell_size",PROPERTY_HINT_RANGE,"1,8192,1"),_SCS("set_cell_size"),_SCS("get_cell_size")); - ADD_PROPERTY( PropertyInfo(Variant::INT,"quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Square,Isometric,Custom"),_SCS("set_mode"),_SCS("get_mode")); ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_set",PROPERTY_HINT_RESOURCE_TYPE,"TileSet"),_SCS("set_tileset"),_SCS("get_tileset")); - ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cell_size",PROPERTY_HINT_RANGE,"1,8192,1",0),_SCS("_set_old_cell_size"),_SCS("_get_old_cell_size")); + ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"cell/size",PROPERTY_HINT_RANGE,"1,8192,1"),_SCS("set_cell_size"),_SCS("get_cell_size")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/quadrant_size",PROPERTY_HINT_RANGE,"1,128,1"),_SCS("set_quadrant_size"),_SCS("get_quadrant_size")); + ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"cell/custom_transform"),_SCS("set_custom_transform"),_SCS("get_custom_transform")); + ADD_PROPERTY( PropertyInfo(Variant::INT,"cell/half_offset",PROPERTY_HINT_ENUM,"Offset X,Offset Y,Disabled"),_SCS("set_half_offset"),_SCS("get_half_offset")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/friction",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_friction"),_SCS("get_collision_friction")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"collision/bounce",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_collision_bounce"),_SCS("get_collision_bounce")); ADD_PROPERTY( PropertyInfo(Variant::INT,"collision/layers",PROPERTY_HINT_ALL_FLAGS),_SCS("set_collision_layer_mask"),_SCS("get_collision_layer_mask")); + ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"tile_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_tile_data"),_SCS("_get_tile_data")); ADD_SIGNAL(MethodInfo("settings_changed")); BIND_CONSTANT( INVALID_CELL ); + BIND_CONSTANT( MODE_SQUARE ); + BIND_CONSTANT( MODE_ISOMETRIC ); + BIND_CONSTANT( MODE_CUSTOM ); + BIND_CONSTANT( HALF_OFFSET_X ); + BIND_CONSTANT( HALF_OFFSET_Y ); + BIND_CONSTANT( HALF_OFFSET_DISABLED ); + } TileMap::TileMap() { @@ -678,12 +862,14 @@ TileMap::TileMap() { pending_update=false; quadrant_order_dirty=false; quadrant_size=16; - cell_size=64; + cell_size=Size2(64,64); center_x=false; center_y=false; collision_layer=1; friction=1; bounce=0; + mode=MODE_SQUARE; + half_offset=HALF_OFFSET_DISABLED; fp_adjust=0.01; fp_adjust=0.01; diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h index d21437e30f..4e9e2e7e97 100644 --- a/scene/2d/tile_map.h +++ b/scene/2d/tile_map.h @@ -37,12 +37,30 @@ class TileMap : public Node2D { OBJ_TYPE( TileMap, Node2D ); +public: + + enum Mode { + MODE_SQUARE, + MODE_ISOMETRIC, + MODE_CUSTOM + }; + + enum HalfOffset { + HALF_OFFSET_X, + HALF_OFFSET_Y, + HALF_OFFSET_DISABLED, + }; +private: Ref<TileSet> tile_set; - int cell_size; + Size2i cell_size; int quadrant_size; bool center_x,center_y; + Mode mode; + Matrix32 custom_transform; + HalfOffset half_offset; + union PosKey { @@ -117,6 +135,12 @@ class TileMap : public Node2D { void _set_tile_data(const DVector<int>& p_data); DVector<int> _get_tile_data() const; + + void _set_old_cell_size(int p_size) { set_cell_size(Size2(p_size,p_size)); } + int _get_old_cell_size() const { return cell_size.x; } + + _FORCE_INLINE_ Vector2 _map_to_world(int p_x,int p_y,bool p_ignore_ofs=false) const; + protected: @@ -132,8 +156,8 @@ public: void set_tileset(const Ref<TileSet>& p_tileset); Ref<TileSet> get_tileset() const; - void set_cell_size(int p_size); - int get_cell_size() const; + void set_cell_size(Size2 p_size); + Size2 get_cell_size() const; void set_quadrant_size(int p_size); int get_quadrant_size() const; @@ -159,10 +183,28 @@ public: void set_collision_bounce(float p_bounce); float get_collision_bounce() const; + void set_mode(Mode p_mode); + Mode get_mode() const; + + void set_half_offset(HalfOffset p_half_offset); + HalfOffset get_half_offset() const; + + void set_custom_transform(const Matrix32& p_xform); + Matrix32 get_custom_transform() const; + + Matrix32 get_cell_transform() const; + Vector2 get_cell_draw_offset() const; + + Vector2 map_to_world(const Vector2& p_pos, bool p_ignore_ofs=false) const; + Vector2 world_to_map(const Vector2& p_pos) const; + void clear(); TileMap(); ~TileMap(); }; +VARIANT_ENUM_CAST(TileMap::Mode); +VARIANT_ENUM_CAST(TileMap::HalfOffset); + #endif // TILE_MAP_H diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp index e5eb193f6f..22534eeb0e 100644 --- a/scene/2d/visibility_notifier_2d.cpp +++ b/scene/2d/visibility_notifier_2d.cpp @@ -64,7 +64,7 @@ void VisibilityNotifier2D::_exit_viewport(Viewport* p_viewport){ void VisibilityNotifier2D::set_rect(const Rect2& p_rect){ rect=p_rect; - if (is_inside_scene()) + if (is_inside_tree()) get_world_2d()->_update_notifier(this,get_global_transform().xform(rect)); _change_notify("rect"); @@ -85,7 +85,7 @@ void VisibilityNotifier2D::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { //get_world_2d()-> get_world_2d()->_register_notifier(this,get_global_transform().xform(rect)); @@ -97,12 +97,12 @@ void VisibilityNotifier2D::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - if (get_scene()->is_editor_hint()) { + if (get_tree()->is_editor_hint()) { draw_rect(rect,Color(1,0.5,1,0.2)); } } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { get_world_2d()->_remove_notifier(this); } break; @@ -190,7 +190,7 @@ void VisibilityEnabler2D::_find_nodes(Node* p_node) { if (add) { - p_node->connect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); + p_node->connect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); nodes[p_node]=meta; _change_node_state(p_node,false); } @@ -207,9 +207,9 @@ void VisibilityEnabler2D::_find_nodes(Node* p_node) { void VisibilityEnabler2D::_notification(int p_what){ - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) return; @@ -222,9 +222,9 @@ void VisibilityEnabler2D::_notification(int p_what){ } - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) return; @@ -235,7 +235,7 @@ void VisibilityEnabler2D::_notification(int p_what){ if (!visible) _change_node_state(E->key(),true); - E->key()->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + E->key()->disconnect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed"); } nodes.clear(); diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp new file mode 100644 index 0000000000..d441abfaf1 --- /dev/null +++ b/scene/2d/y_sort.cpp @@ -0,0 +1,29 @@ +#include "y_sort.h" + + + +void YSort::set_sort_enabled(bool p_enabled) { + + sort_enabled=p_enabled; + VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(),sort_enabled); +} + +bool YSort::is_sort_enabled() const { + + return sort_enabled; +} + +void YSort::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_sort_enabled","enabled"),&YSort::set_sort_enabled); + ObjectTypeDB::bind_method(_MD("is_sort_enabled"),&YSort::is_sort_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"sort/enabled"),_SCS("set_sort_enabled"),_SCS("is_sort_enabled")); +} + + +YSort::YSort() { + + sort_enabled=true; + VS::get_singleton()->canvas_item_set_sort_children_by_y(get_canvas_item(),true); +} diff --git a/scene/2d/y_sort.h b/scene/2d/y_sort.h new file mode 100644 index 0000000000..6d04a67e42 --- /dev/null +++ b/scene/2d/y_sort.h @@ -0,0 +1,17 @@ +#ifndef Y_SORT_H +#define Y_SORT_H + +#include "scene/2d/node_2d.h" + +class YSort : public Node2D { + OBJ_TYPE(YSort,Node2D); + bool sort_enabled; + static void _bind_methods(); +public: + + void set_sort_enabled(bool p_enabled); + bool is_sort_enabled() const; + YSort(); +}; + +#endif // Y_SORT_H diff --git a/scene/3d/SCsub b/scene/3d/SCsub index 6789851aab..3c2144bedc 100644 --- a/scene/3d/SCsub +++ b/scene/3d/SCsub @@ -1,7 +1,6 @@ Import('env') -print("V: "+env["disable_3d"]) if (env["disable_3d"]=="yes"): env.scene_sources.append("3d/spatial.cpp") diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp index f5895453cc..9cdd24d102 100644 --- a/scene/3d/area.cpp +++ b/scene/3d/area.cpp @@ -94,7 +94,7 @@ real_t Area::get_priority() const{ } -void Area::_body_enter_scene(ObjectID p_id) { +void Area::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = obj ? obj->cast_to<Node>() : NULL; @@ -102,9 +102,9 @@ void Area::_body_enter_scene(ObjectID p_id) { Map<ObjectID,BodyState>::Element *E=body_map.find(p_id); ERR_FAIL_COND(!E); - ERR_FAIL_COND(E->get().in_scene); + ERR_FAIL_COND(E->get().in_tree); - E->get().in_scene=true; + E->get().in_tree=true; emit_signal(SceneStringNames::get_singleton()->body_enter,node); for(int i=0;i<E->get().shapes.size();i++) { @@ -113,15 +113,16 @@ void Area::_body_enter_scene(ObjectID p_id) { } -void Area::_body_exit_scene(ObjectID p_id) { +void Area::_body_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,BodyState>::Element *E=body_map.find(p_id); ERR_FAIL_COND(!E); - ERR_FAIL_COND(!E->get().in_scene); - E->get().in_scene=false; + ERR_FAIL_COND(!E->get().in_tree); + E->get().in_tree=false; emit_signal(SceneStringNames::get_singleton()->body_exit,node); for(int i=0;i<E->get().shapes.size();i++) { @@ -132,6 +133,7 @@ void Area::_body_exit_scene(ObjectID p_id) { void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape) { + bool body_in = p_status==PhysicsServer::AREA_BODY_ADDED; ObjectID objid=p_instance; @@ -142,16 +144,18 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod ERR_FAIL_COND(!body_in && !E); + locked=true; + if (body_in) { if (!E) { E = body_map.insert(objid,BodyState()); E->get().rc=0; - E->get().in_scene=node && node->is_inside_scene(); + E->get().in_tree=node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); - if (E->get().in_scene) { + node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid)); + if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_enter,node); } } @@ -162,7 +166,7 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod E->get().shapes.insert(ShapePair(p_body_shape,p_area_shape)); - if (E->get().in_scene) { + if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_area_shape); } @@ -178,9 +182,9 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod if (E->get().rc==0) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); - node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); - if (E->get().in_scene) + 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); + if (E->get().in_tree) emit_signal(SceneStringNames::get_singleton()->body_exit,obj); } @@ -188,7 +192,7 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod eraseit=true; } - if (node && E->get().in_scene) { + if (node && E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_area_shape); } @@ -197,11 +201,19 @@ void Area::_body_inout(int p_status,const RID& p_body, int p_instance, int p_bod } + locked=false; + + } void Area::_clear_monitoring() { + if (locked) { + ERR_EXPLAIN("This function can't be used during the in/out signal."); + } + ERR_FAIL_COND(locked); + Map<ObjectID,BodyState> bmcopy = body_map; body_map.clear(); //disconnect all monitored stuff @@ -211,7 +223,7 @@ void Area::_clear_monitoring() { Object *obj = ObjectDB::get_instance(E->key()); Node *node = obj ? obj->cast_to<Node>() : NULL; ERR_CONTINUE(!node); - if (!E->get().in_scene) + if (!E->get().in_tree) continue; for(int i=0;i<E->get().shapes.size();i++) { @@ -221,20 +233,25 @@ void Area::_clear_monitoring() { emit_signal(SceneStringNames::get_singleton()->body_exit,obj); - node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); - node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); + 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); } } void Area::_notification(int p_what) { - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { _clear_monitoring(); } } void Area::set_enable_monitoring(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==monitoring) return; @@ -255,21 +272,29 @@ bool Area::is_monitoring_enabled() const { } -void Area::set_ray_pickable(bool p_ray_pickable) { +Array Area::get_overlapping_bodies() const { - ray_pickable=p_ray_pickable; - PhysicsServer::get_singleton()->area_set_ray_pickable(get_rid(),p_ray_pickable); -} + ERR_FAIL_COND_V(!monitoring,Array()); + Array ret; + ret.resize(body_map.size()); + int idx=0; + for (const Map<ObjectID,BodyState>::Element *E=body_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; + } -bool Area::is_ray_pickable() const { + } - return ray_pickable; + return ret; } void Area::_bind_methods() { - ObjectTypeDB::bind_method(_MD("_body_enter_scene","id"),&Area::_body_enter_scene); - ObjectTypeDB::bind_method(_MD("_body_exit_scene","id"),&Area::_body_exit_scene); + 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("set_space_override_mode","enable"),&Area::set_space_override_mode); ObjectTypeDB::bind_method(_MD("get_space_override_mode"),&Area::get_space_override_mode); @@ -289,12 +314,12 @@ void Area::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_priority","priority"),&Area::set_priority); ObjectTypeDB::bind_method(_MD("get_priority"),&Area::get_priority); - ObjectTypeDB::bind_method(_MD("set_ray_pickable","ray_pickable"),&Area::set_ray_pickable); - ObjectTypeDB::bind_method(_MD("is_ray_pickable"),&Area::is_ray_pickable); 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("_body_inout"),&Area::_body_inout); @@ -310,7 +335,6 @@ void Area::_bind_methods() { ADD_PROPERTY( PropertyInfo(Variant::REAL,"density",PROPERTY_HINT_RANGE,"0,1024,0.001"),_SCS("set_density"),_SCS("get_density")); 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,"ray_pickable"),_SCS("set_ray_pickable"),_SCS("is_ray_pickable")); } @@ -318,12 +342,13 @@ Area::Area() : CollisionObject(PhysicsServer::get_singleton()->area_create(),tru space_override=SPACE_OVERRIDE_DISABLED; set_gravity(9.8);; + locked=false; set_gravity_vector(Vector3(0,-1,0)); gravity_is_point=false; density=0.1; priority=0; monitoring=false; - ray_pickable=false; + set_ray_pickable(false); set_enable_monitoring(true); } diff --git a/scene/3d/area.h b/scene/3d/area.h index 92b5d39f59..40c6d24b5c 100644 --- a/scene/3d/area.h +++ b/scene/3d/area.h @@ -52,12 +52,13 @@ private: real_t density; int priority; bool monitoring; - bool ray_pickable; + bool locked; + void _body_inout(int p_status,const RID& p_body, int p_instance, int p_body_shape,int p_area_shape); - void _body_enter_scene(ObjectID p_id); - void _body_exit_scene(ObjectID p_id); + void _body_enter_tree(ObjectID p_id); + void _body_exit_tree(ObjectID p_id); struct ShapePair { @@ -77,7 +78,7 @@ private: struct BodyState { int rc; - bool in_scene; + bool in_tree; VSet<ShapePair> shapes; }; @@ -109,12 +110,11 @@ public: void set_priority(real_t p_priority); real_t get_priority() const; - void set_ray_pickable(bool p_ray_pickable); - bool is_ray_pickable() const; - void set_enable_monitoring(bool p_enable); bool is_monitoring_enabled() const; + Array get_overlapping_bodies() const; + Area(); ~Area(); diff --git a/scene/3d/baked_light_instance.cpp b/scene/3d/baked_light_instance.cpp index c1cc1f6b68..b55093a779 100644 --- a/scene/3d/baked_light_instance.cpp +++ b/scene/3d/baked_light_instance.cpp @@ -63,3 +63,81 @@ BakedLightInstance::BakedLightInstance() { } +///////////////////////// + + +void BakedLightSampler::set_param(Param p_param,float p_value) { + ERR_FAIL_INDEX(p_param,PARAM_MAX); + params[p_param]=p_value; + VS::get_singleton()->baked_light_sampler_set_param(base,VS::BakedLightSamplerParam(p_param),p_value); +} + +float BakedLightSampler::get_param(Param p_param) const{ + + ERR_FAIL_INDEX_V(p_param,PARAM_MAX,0); + return params[p_param]; + +} + +void BakedLightSampler::set_resolution(int p_resolution){ + + ERR_FAIL_COND(p_resolution<4 && p_resolution>32); + resolution=p_resolution; + VS::get_singleton()->baked_light_sampler_set_resolution(base,resolution); +} +int BakedLightSampler::get_resolution() const { + + return resolution; +} + +AABB BakedLightSampler::get_aabb() const { + + float r = get_param(PARAM_RADIUS); + return AABB( Vector3(-r,-r,-r),Vector3(r*2,r*2,r*2)); +} +DVector<Face3> BakedLightSampler::get_faces(uint32_t p_usage_flags) const { + return DVector<Face3>(); +} + +void BakedLightSampler::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_param","param","value"),&BakedLightSampler::set_param); + ObjectTypeDB::bind_method(_MD("get_param","param"),&BakedLightSampler::get_param); + + ObjectTypeDB::bind_method(_MD("set_resolution","resolution"),&BakedLightSampler::set_resolution); + ObjectTypeDB::bind_method(_MD("get_resolution"),&BakedLightSampler::get_resolution); + + + BIND_CONSTANT( PARAM_RADIUS ); + BIND_CONSTANT( PARAM_STRENGTH ); + BIND_CONSTANT( PARAM_ATTENUATION ); + BIND_CONSTANT( PARAM_DETAIL_RATIO ); + BIND_CONSTANT( PARAM_MAX ); + + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/radius",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_RADIUS); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/strength",PROPERTY_HINT_RANGE,"0.01,16,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_STRENGTH); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/attenuation",PROPERTY_HINT_EXP_EASING),_SCS("set_param"),_SCS("get_param"),PARAM_ATTENUATION); + ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/detail_ratio",PROPERTY_HINT_RANGE,"0.01,1.0,0.01"),_SCS("set_param"),_SCS("get_param"),PARAM_DETAIL_RATIO); +// ADD_PROPERTYI( PropertyInfo(Variant::REAL,"params/detail_ratio",PROPERTY_HINT_RANGE,"0,20,1"),_SCS("set_param"),_SCS("get_param"),PARAM_DETAIL_RATIO); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"params/resolution",PROPERTY_HINT_RANGE,"4,32,1"),_SCS("set_resolution"),_SCS("get_resolution")); + +} + +BakedLightSampler::BakedLightSampler() { + + base = VS::get_singleton()->baked_light_sampler_create(); + set_base(base); + + params[PARAM_RADIUS]=1.0; + params[PARAM_STRENGTH]=1.0; + params[PARAM_ATTENUATION]=1.0; + params[PARAM_DETAIL_RATIO]=0.1; + resolution=16; + + +} + +BakedLightSampler::~BakedLightSampler(){ + + VS::get_singleton()->free(base); +} diff --git a/scene/3d/baked_light_instance.h b/scene/3d/baked_light_instance.h index b904ced9a7..0694c813ce 100644 --- a/scene/3d/baked_light_instance.h +++ b/scene/3d/baked_light_instance.h @@ -30,4 +30,46 @@ public: BakedLightInstance(); }; + + +class BakedLightSampler : public VisualInstance { + OBJ_TYPE(BakedLightSampler,VisualInstance); + + +public: + + enum Param { + PARAM_RADIUS=VS::BAKED_LIGHT_SAMPLER_RADIUS, + PARAM_STRENGTH=VS::BAKED_LIGHT_SAMPLER_STRENGTH, + PARAM_ATTENUATION=VS::BAKED_LIGHT_SAMPLER_ATTENUATION, + PARAM_DETAIL_RATIO=VS::BAKED_LIGHT_SAMPLER_DETAIL_RATIO, + PARAM_MAX=VS::BAKED_LIGHT_SAMPLER_MAX + }; + + + +protected: + + RID base; + float params[PARAM_MAX]; + int resolution; + static void _bind_methods(); +public: + + virtual AABB get_aabb() const; + virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; + + void set_param(Param p_param,float p_value); + float get_param(Param p_param) const; + + void set_resolution(int p_resolution); + int get_resolution() const; + + BakedLightSampler(); + ~BakedLightSampler(); +}; + +VARIANT_ENUM_CAST( BakedLightSampler::Param ); + + #endif // BAKED_LIGHT_H diff --git a/scene/3d/body_shape.cpp b/scene/3d/body_shape.cpp index b291ce7c72..287515dce7 100644 --- a/scene/3d/body_shape.cpp +++ b/scene/3d/body_shape.cpp @@ -44,7 +44,6 @@ void CollisionShape::_update_body() { - if (get_parent() && get_parent()->cast_to<CollisionObject>()) get_parent()->cast_to<CollisionObject>()->_update_shapes_from_children(); @@ -72,7 +71,7 @@ void CollisionShape::make_convex_from_brothers() { } } - +/* void CollisionShape::_update_indicator() { @@ -300,9 +299,12 @@ void CollisionShape::_update_indicator() { } - +*/ void CollisionShape::_add_to_collision_object(Object* p_cshape) { + if (unparenting) + return; + CollisionObject *co=p_cshape->cast_to<CollisionObject>(); ERR_FAIL_COND(!co); @@ -318,22 +320,25 @@ void CollisionShape::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_WORLD: { - indicator_instance = VisualServer::get_singleton()->instance_create2(indicator,get_world()->get_scenario()); + case NOTIFICATION_ENTER_TREE: { + unparenting=false; + + //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()); + // VisualServer::get_singleton()->instance_set_transform(indicator_instance,get_global_transform()); if (updating_body) { _update_body(); } } break; - case NOTIFICATION_EXIT_WORLD: { - if (indicator_instance.is_valid()) { + case NOTIFICATION_EXIT_TREE: { + /* if (indicator_instance.is_valid()) { VisualServer::get_singleton()->free(indicator_instance); indicator_instance=RID(); - } + }*/ } break; case NOTIFICATION_UNPARENTED: { + unparenting=true; if (updating_body) _update_body(); } break; @@ -411,15 +416,16 @@ bool CollisionShape::is_trigger() const{ CollisionShape::CollisionShape() { - indicator = VisualServer::get_singleton()->mesh_create(); + //indicator = VisualServer::get_singleton()->mesh_create(); updating_body=true; + unparenting=false; trigger=false; } CollisionShape::~CollisionShape() { if (!shape.is_null()) shape->unregister_owner(this); - VisualServer::get_singleton()->free(indicator); + //VisualServer::get_singleton()->free(indicator); } #if 0 diff --git a/scene/3d/body_shape.h b/scene/3d/body_shape.h index d1cb229f70..b3fbaca178 100644 --- a/scene/3d/body_shape.h +++ b/scene/3d/body_shape.h @@ -37,19 +37,23 @@ class CollisionShape : public Spatial { OBJ_TYPE( CollisionShape, Spatial ); OBJ_CATEGORY("3D Physics Nodes"); + Ref<Shape> shape; + + /* RID _get_visual_instance_rid() const; - Ref<Shape> shape; void _update_indicator(); RID material; RID indicator; RID indicator_instance; + */ void resource_changed(RES res); bool updating_body; + bool unparenting; bool trigger; void _update_body(); diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp index cbc4abb7a9..6bbb957d25 100644 --- a/scene/3d/bone_attachment.cpp +++ b/scene/3d/bone_attachment.cpp @@ -102,12 +102,12 @@ void BoneAttachment::_check_unbind() { void BoneAttachment::set_bone_name(const String& p_name) { - if (is_inside_scene()) + if (is_inside_tree()) _check_unbind(); bone_name=p_name; - if (is_inside_scene()) + if (is_inside_tree()) _check_bind(); } @@ -120,11 +120,11 @@ void BoneAttachment::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { _check_bind(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { _check_unbind(); } break; diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp index 4245bfa2c9..27420f8002 100644 --- a/scene/3d/camera.cpp +++ b/scene/3d/camera.cpp @@ -86,6 +86,10 @@ bool Camera::_set(const StringName& p_name, const Variant& p_value) { set_keep_aspect_mode(KeepAspect(int(p_value))); else if (p_name=="vaspect") set_keep_aspect_mode(p_value?KEEP_WIDTH:KEEP_HEIGHT); + else if (p_name=="h_offset") + h_offset=p_value; + else if (p_name=="v_offset") + v_offset=p_value; else if (p_name=="current") { if (p_value.operator bool()) { make_current(); @@ -121,13 +125,17 @@ bool Camera::_get(const StringName& p_name,Variant &r_ret) const { r_ret= int(keep_aspect); else if (p_name=="current") { - if (is_inside_scene() && get_scene()->is_editor_hint()) { + if (is_inside_tree() && get_tree()->is_editor_hint()) { r_ret=current; } else { r_ret=is_current(); } } else if (p_name=="visible_layers") { r_ret=get_visible_layers(); + } else if (p_name=="h_offset") { + r_ret=get_h_offset(); + } else if (p_name=="v_offset") { + r_ret=get_v_offset(); } else if (p_name=="environment") { r_ret=get_environment(); } else @@ -170,19 +178,23 @@ void Camera::_get_property_list( List<PropertyInfo> *p_list) const { p_list->push_back( PropertyInfo( Variant::BOOL, "current" ) ); p_list->push_back( PropertyInfo( Variant::INT, "visible_layers",PROPERTY_HINT_ALL_FLAGS ) ); p_list->push_back( PropertyInfo( Variant::OBJECT, "environment",PROPERTY_HINT_RESOURCE_TYPE,"Environment" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "h_offset" ) ); + p_list->push_back( PropertyInfo( Variant::REAL, "v_offset" ) ); } void Camera::_update_camera() { Transform tr = get_camera_transform(); + tr.origin+=tr.basis.get_axis(1)*v_offset; + tr.origin+=tr.basis.get_axis(0)*h_offset; VisualServer::get_singleton()->camera_set_transform( camera, tr ); // here goes listener stuff // if (viewport_ptr && is_inside_scene() && is_current()) // viewport_ptr->_camera_transform_changed_notify(); - if (is_inside_scene() && is_current()) { + if (is_inside_tree() && is_current()) { if (viewport_ptr) { viewport_ptr->_camera_transform_changed_notify(); } @@ -219,11 +231,14 @@ void Camera::_notification(int p_what) { } + camera_group = "_vp_cameras"+itos(get_viewport()->get_instance_ID()); + add_to_group(camera_group); if (viewport_ptr) viewport_ptr->cameras.insert(this); if (current) make_current(); + } break; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -241,6 +256,8 @@ void Camera::_notification(int p_what) { if (viewport_ptr) viewport_ptr->cameras.erase(this); viewport_ptr=NULL; + remove_from_group(camera_group); + } break; case NOTIFICATION_BECAME_CURRENT: { @@ -262,7 +279,7 @@ void Camera::_notification(int p_what) { Transform Camera::get_camera_transform() const { - return get_global_transform(); + return get_global_transform().orthonormalized(); } void Camera::set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far) { @@ -304,7 +321,7 @@ void Camera::make_current() { current=true; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (viewport_ptr) { @@ -314,22 +331,40 @@ void Camera::make_current() { //get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this); } + +void Camera::_camera_make_next_current(Node *p_exclude) { + + if (this==p_exclude) + return; + if (!is_inside_tree()) + return; + if (get_viewport()->get_camera()!=NULL) + return; + + make_current(); +} + + void Camera::clear_current() { current=false; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (viewport_ptr) { - if (viewport_ptr->get_camera()==this) + if (viewport_ptr->get_camera()==this) { viewport_ptr->_set_camera(NULL); + //a group is used beause this needs to be in order to be deterministic + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,camera_group,"_camera_make_next_current",this); + + } } } bool Camera::is_current() const { - if (is_inside_scene()) { + if (is_inside_tree()) { if (viewport_ptr) return viewport_ptr->get_camera()==this; } else @@ -439,12 +474,20 @@ Vector3 Camera::project_ray_normal(const Point2& p_pos) const { Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const { - if (!is_inside_scene()) { + if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); - ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + ERR_FAIL_COND_V(!is_inside_tree(),Vector3()); } + +#if 0 Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Vector2 cpos = p_pos; +#else + + Size2 viewport_size = viewport_ptr->get_camera_rect_size(); + Vector2 cpos = viewport_ptr->get_camera_coords(p_pos); +#endif Vector3 ray; @@ -456,23 +499,28 @@ Vector3 Camera::project_local_ray_normal(const Point2& p_pos) const { cm.set_perspective(fov,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH); float screen_w,screen_h; cm.get_viewport_size(screen_w,screen_h); - ray=Vector3( ((p_pos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(p_pos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized(); + ray=Vector3( ((cpos.x/viewport_size.width)*2.0-1.0)*screen_w, ((1.0-(cpos.y/viewport_size.height))*2.0-1.0)*screen_h,-near).normalized(); } - return ray; }; Vector3 Camera::project_ray_origin(const Point2& p_pos) const { - if (!is_inside_scene()) { + if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); - ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + ERR_FAIL_COND_V(!is_inside_tree(),Vector3()); } +#if 0 Size2 viewport_size = viewport_ptr->get_visible_rect().size; + Vector2 cpos = p_pos; +#else + Size2 viewport_size = viewport_ptr->get_camera_rect_size(); + Vector2 cpos = viewport_ptr->get_camera_coords(p_pos); +#endif ERR_FAIL_COND_V( viewport_size.y == 0, Vector3() ); // float aspect = viewport_size.x / viewport_size.y; @@ -482,7 +530,7 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const { return get_camera_transform().origin; } else { - Vector2 pos = p_pos / viewport_size; + Vector2 pos = cpos / viewport_size; float vsize,hsize; if (keep_aspect==KEEP_WIDTH) { vsize = size/viewport_size.get_aspect(); @@ -493,6 +541,8 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const { } + + Vector3 ray; ray.x = pos.x * (hsize) - hsize/2; ray.y = (1.0 - pos.y) * (vsize) - vsize/2; @@ -504,9 +554,9 @@ Vector3 Camera::project_ray_origin(const Point2& p_pos) const { Point2 Camera::unproject_position(const Vector3& p_pos) const { - if (!is_inside_scene()) { + if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); - ERR_FAIL_COND_V(!is_inside_scene(),Vector2()); + ERR_FAIL_COND_V(!is_inside_tree(),Vector2()); } Size2 viewport_size = viewport_ptr->get_visible_rect().size; @@ -535,9 +585,9 @@ Point2 Camera::unproject_position(const Vector3& p_pos) const { Vector3 Camera::project_position(const Point2& p_point) const { - if (!is_inside_scene()) { + if (!is_inside_tree()) { ERR_EXPLAIN("Camera is not inside scene."); - ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + ERR_FAIL_COND_V(!is_inside_tree(),Vector3()); } Size2 viewport_size = viewport_ptr->get_visible_rect().size; @@ -636,6 +686,7 @@ void Camera::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_environment:Environment"),&Camera::get_environment); ObjectTypeDB::bind_method(_MD("set_keep_aspect_mode","mode"),&Camera::set_keep_aspect_mode); ObjectTypeDB::bind_method(_MD("get_keep_aspect_mode"),&Camera::get_keep_aspect_mode); + ObjectTypeDB::bind_method(_MD("_camera_make_next_current"),&Camera::_camera_make_next_current); //ObjectTypeDB::bind_method( _MD("_camera_make_current"),&Camera::_camera_make_current ); BIND_CONSTANT( PROJECTION_PERSPECTIVE ); @@ -695,7 +746,7 @@ Vector<Plane> Camera::get_frustum() const { else cm.set_orthogonal(size,viewport_size.get_aspect(),near,far,keep_aspect==KEEP_WIDTH); - return cm.get_projection_planes(get_global_transform()); + return cm.get_projection_planes(get_camera_transform()); } @@ -704,7 +755,7 @@ Vector<Plane> Camera::get_frustum() const { void Camera::look_at(const Vector3& p_target, const Vector3& p_up_normal) { Transform lookat; - lookat.origin=get_global_transform().origin; + lookat.origin=get_camera_transform().origin; lookat=lookat.looking_at(p_target,p_up_normal); set_global_transform(lookat); } @@ -718,6 +769,27 @@ void Camera::look_at_from_pos(const Vector3& p_pos,const Vector3& p_target, cons } +void Camera::set_v_offset(float p_offset) { + + v_offset=p_offset; + _update_camera();; +} + +float Camera::get_v_offset() const { + + return v_offset; +} + +void Camera::set_h_offset(float p_offset) { + h_offset=p_offset; + _update_camera(); +} + +float Camera::get_h_offset() const { + + return h_offset; +} + Camera::Camera() { @@ -732,7 +804,10 @@ Camera::Camera() { mode=PROJECTION_PERSPECTIVE; set_perspective(60.0,0.1,100.0); keep_aspect=KEEP_HEIGHT; - layers=0xFFFFFFFF; + layers=0xfffff; + v_offset=0; + h_offset=0; + VisualServer::get_singleton()->camera_set_visible_layers(camera,layers); //active=false; } diff --git a/scene/3d/camera.h b/scene/3d/camera.h index 014c7cb520..950688dfda 100644 --- a/scene/3d/camera.h +++ b/scene/3d/camera.h @@ -61,11 +61,15 @@ private: float fov; float size; float near,far; + float v_offset; + float h_offset; KeepAspect keep_aspect; RID camera; RID scenario_id; + String camera_group; + uint32_t layers; Viewport *viewport_ptr; @@ -74,6 +78,7 @@ private: virtual bool _can_gizmo_scale() const; virtual RES _get_gizmo_geometry() const; + void _camera_make_next_current(Node *p_exclude); //void _camera_make_current(Node *p_camera); @@ -137,6 +142,12 @@ 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_v_offset(float p_offset); + float get_v_offset() const; + + void set_h_offset(float p_offset); + float get_h_offset() const; + Camera(); ~Camera(); diff --git a/scene/3d/car_body.cpp b/scene/3d/car_body.cpp deleted file mode 100644 index a21598b07c..0000000000 --- a/scene/3d/car_body.cpp +++ /dev/null @@ -1,741 +0,0 @@ -/*************************************************************************/ -/* car_body.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "car_body.h" - -#define DEG2RADMUL (Math_PI/180.0) -#define RAD2DEGMUL (180.0/Math_PI) - -void CarWheel::_notification(int p_what) { - - - if (p_what==NOTIFICATION_ENTER_SCENE) { - - if (!get_parent()) - return; - CarBody *cb = get_parent()->cast_to<CarBody>(); - if (!cb) - return; - body=cb; - local_xform=get_transform(); - cb->wheels.push_back(this); - } - if (p_what==NOTIFICATION_EXIT_SCENE) { - - if (!get_parent()) - return; - CarBody *cb = get_parent()->cast_to<CarBody>(); - if (!cb) - return; - cb->wheels.erase(this); - body=NULL; - } -} - -void CarWheel::set_side_friction(real_t p_friction) { - - side_friction=p_friction; -} -void CarWheel::set_forward_friction(real_t p_friction) { - - forward_friction=p_friction; -} -void CarWheel::set_travel(real_t p_travel) { - - travel=p_travel; - update_gizmo(); - -} -void CarWheel::set_radius(real_t p_radius) { - - radius=p_radius; - update_gizmo(); - -} -void CarWheel::set_resting_frac(real_t p_frac) { - - resting_frac=p_frac; -} -void CarWheel::set_damping_frac(real_t p_frac) { - - damping_frac=p_frac; -} -void CarWheel::set_num_rays(real_t p_rays) { - - num_rays=p_rays; -} - -real_t CarWheel::get_side_friction() const{ - - return side_friction; -} -real_t CarWheel::get_forward_friction() const{ - - return forward_friction; -} -real_t CarWheel::get_travel() const{ - - return travel; -} -real_t CarWheel::get_radius() const{ - - return radius; -} -real_t CarWheel::get_resting_frac() const{ - - return resting_frac; -} -real_t CarWheel::get_damping_frac() const{ - - return damping_frac; -} - -int CarWheel::get_num_rays() const{ - - return num_rays; -} - - -void CarWheel::update(real_t dt) { - - - if (dt <= 0.0f) - return; - - float origAngVel = angVel; - - if (locked) - { - angVel = 0; - torque = 0; - } - else - { - - float wheelMass = 0.03f * body->mass; - float inertia = 0.5f * (radius * radius) * wheelMass; - - angVel += torque * dt / inertia; - torque = 0; - - // prevent friction from reversing dir - todo do this better - // by limiting the torque - if (((origAngVel > angVelForGrip) && (angVel < angVelForGrip)) || - ((origAngVel < angVelForGrip) && (angVel > angVelForGrip))) - angVel = angVelForGrip; - - angVel += driveTorque * dt / inertia; - driveTorque = 0; - - float maxAngVel = 200; - print_line("angvel: "+rtos(angVel)); - angVel = CLAMP(angVel, -maxAngVel, maxAngVel); - - axisAngle += Math::rad2deg(dt * angVel); - } -} - -bool CarWheel::add_forces(PhysicsDirectBodyState *s) { - - - Vector3 force; - - PhysicsDirectSpaceState *space = s->get_space_state(); - - Transform world = s->get_transform() * local_xform; - - // OpenGl has differnet row/column order for matrixes than XNA has .. - //Vector3 wheelFwd = world.get_basis().get_axis(Vector3::AXIS_Z); - //Vector3 wheelFwd = RotationMatrix(mSteerAngle, worldAxis) * carBody.GetOrientation().GetCol(0); - Vector3 wheelUp = world.get_basis().get_axis(Vector3::AXIS_Y); - Vector3 wheelFwd = Matrix3(wheelUp,Math::deg2rad(steerAngle)).xform( world.get_basis().get_axis(Vector3::AXIS_Z) ); - Vector3 wheelLeft = -wheelUp.cross(wheelFwd).normalized(); - Vector3 worldPos = world.origin; - Vector3 worldAxis = wheelUp; - - // start of ray - float rayLen = 2.0f * radius + travel; - Vector3 wheelRayEnd = worldPos - radius * worldAxis; - Vector3 wheelRayBegin = wheelRayEnd + rayLen * worldAxis; - //wheelRayEnd = -rayLen * worldAxis; - - //Assert(PhysicsSystem.CurrentPhysicsSystem); - - - ///Assert(collSystem); - /// - const int maxNumRays = 32; - - int numRaysUse = MIN(num_rays, maxNumRays); - - // adjust the start position of the ray - divide the wheel into numRays+2 - // rays, but don't use the first/last. - float deltaFwd = (2.0f * radius) / (numRaysUse + 1); - float deltaFwdStart = deltaFwd; - - float fracs[maxNumRays]; - Vector3 segmentEnds[maxNumRays]; - Vector3 groundPositions[maxNumRays]; - Vector3 groundNormals[maxNumRays]; - - - lastOnFloor = false; - int bestIRay = 0; - int iRay; - - - for (iRay = 0; iRay < numRaysUse; ++iRay) - { - fracs[iRay] = 1e20; - // work out the offset relative to the middle ray - float distFwd = (deltaFwdStart + iRay * deltaFwd) - radius; - float zOffset = radius * (1.0f - (float)Math::cos( Math::deg2rad( 90.0f * (distFwd / radius)))); - - segmentEnds[iRay] = wheelRayEnd + distFwd * wheelFwd + zOffset * wheelUp; - - - PhysicsDirectSpaceState::RayResult rr; - - bool collided = space->intersect_ray(wheelRayBegin,segmentEnds[iRay],rr,body->exclude); - - - if (collided){ - lastOnFloor = true; - groundPositions[iRay]=rr.position; - groundNormals[iRay]=rr.normal; - fracs[iRay] = ((wheelRayBegin-rr.position).length() / (wheelRayBegin-wheelRayEnd).length()); - if (fracs[iRay] < fracs[bestIRay]) - bestIRay = iRay; - } - } - - - if (!lastOnFloor) - return false; - - //Assert(bestIRay < numRays); - - // use the best one - Vector3 groundPos = groundPositions[bestIRay]; - float frac = fracs[bestIRay]; - - // const Vector3 groundNormal = (worldPos - segments[bestIRay].GetEnd()).NormaliseSafe(); - // const Vector3 groundNormal = groundNormals[bestIRay]; - - - Vector3 groundNormal = worldAxis; - - if (numRaysUse > 1) - { - for (iRay = 0; iRay < numRaysUse; ++iRay) - { - if (fracs[iRay] <= 1.0f) - { - groundNormal += (1.0f - fracs[iRay]) * (worldPos - segmentEnds[iRay]); - } - } - - groundNormal.normalize(); - - } - else - { - groundNormal = groundNormals[bestIRay]; - } - - - - float spring = (body->mass/body->wheels.size()) * s->get_total_gravity().length() / (resting_frac * travel); - - float displacement = rayLen * (1.0f - frac); - displacement = CLAMP(displacement, 0, travel); - - - - float displacementForceMag = displacement * spring; - - // reduce force when suspension is par to ground - displacementForceMag *= groundNormals[bestIRay].dot(worldAxis); - - // apply damping - float damping = 2.0f * (float)Math::sqrt(spring * body->mass); - damping /= body->wheels.size(); // assume wheels act together - damping *= damping_frac; // a bit bouncy - - float upSpeed = (displacement - lastDisplacement) / s->get_step(); - - float dampingForceMag = upSpeed * damping; - - float totalForceMag = displacementForceMag + dampingForceMag; - - if (totalForceMag < 0.0f) totalForceMag = 0.0f; - - Vector3 extraForce = totalForceMag * worldAxis; - - - force += extraForce; - // side-slip friction and drive force. Work out wheel- and floor-relative coordinate frame - Vector3 groundUp = groundNormal; - Vector3 groundLeft = groundNormal.cross(wheelFwd).normalized(); - - Vector3 groundFwd = groundLeft.cross(groundUp); - - Vector3 wheelPointVel = s->get_linear_velocity() + - (s->get_angular_velocity()).cross(s->get_transform().basis.xform(local_xform.origin));// * mPos); - - Vector3 rimVel = -angVel * wheelLeft.cross(groundPos - worldPos); - wheelPointVel += rimVel; - - // if sitting on another body then adjust for its velocity. - /*if (worldBody != null) - { - Vector3 worldVel = worldBody.Velocity + - Vector3.Cross(worldBody.AngularVelocity, groundPos - worldBody.Position); - - wheelPointVel -= worldVel; - }*/ - - // sideways forces - float noslipVel = 0.2f; - float slipVel = 0.4f; - float slipFactor = 0.7f; - - float smallVel = 3; - float friction = side_friction; - - float sideVel = wheelPointVel.dot(groundLeft); - - if ((sideVel > slipVel) || (sideVel < -slipVel)) - friction *= slipFactor; - else - if ((sideVel > noslipVel) || (sideVel < -noslipVel)) - friction *= 1.0f - (1.0f - slipFactor) * (Math::absf(sideVel) - noslipVel) / (slipVel - noslipVel); - - if (sideVel < 0.0f) - friction *= -1.0f; - - if (Math::absf(sideVel) < smallVel) - friction *= Math::absf(sideVel) / smallVel; - - float sideForce = -friction * totalForceMag; - - extraForce = sideForce * groundLeft; - force += extraForce; - // fwd/back forces - friction = forward_friction; - float fwdVel = wheelPointVel.dot(groundFwd); - - if ((fwdVel > slipVel) || (fwdVel < -slipVel)) - friction *= slipFactor; - else - if ((fwdVel > noslipVel) || (fwdVel < -noslipVel)) - friction *= 1.0f - (1.0f - slipFactor) * (Math::absf(fwdVel) - noslipVel) / (slipVel - noslipVel); - - if (fwdVel < 0.0f) - friction *= -1.0f; - - if (Math::absf(fwdVel) < smallVel) - friction *= Math::absf(fwdVel) / smallVel; - - float fwdForce = -friction * totalForceMag; - - extraForce = fwdForce * groundFwd; - force += extraForce; - - - //if (!force.IsSensible()) - //{ - // TRACE_FILE_IF(ONCE_1) - // TRACE("Bad force in car wheel\n"); - // return true; - //} - - // fwd force also spins the wheel - Vector3 wheelCentreVel = s->get_linear_velocity() + - (s->get_angular_velocity()).cross(s->get_transform().basis.xform(local_xform.origin)); - - angVelForGrip = wheelCentreVel.dot(groundFwd) / radius; - torque += -fwdForce * radius; - - // add force to car -// carBody.AddWorldForce(force, groundPos); - - s->add_force(force,(groundPos-s->get_transform().origin)); - - // add force to the world - /* - if (worldBody != null && !worldBody.Immovable) - { - // todo get the position in the right place... - // also limit the velocity that this force can produce by looking at the - // mass/inertia of the other object - float maxOtherBodyAcc = 500.0f; - float maxOtherBodyForce = maxOtherBodyAcc * worldBody.Mass; - - if (force.LengthSquared() > (maxOtherBodyForce * maxOtherBodyForce)) - force *= maxOtherBodyForce / force.Length(); - - worldBody.AddWorldForce(-force, groundPos); - }*/ - - Transform wheel_xf = local_xform; - wheel_xf.origin += wheelUp * displacement; - wheel_xf.basis = wheel_xf.basis * Matrix3(Vector3(0,1,0),Math::deg2rad(steerAngle)); - //wheel_xf.basis = wheel_xf.basis * Matrix3(wheel_xf.basis[0],-Math::deg2rad(axisAngle)); - - set_transform(wheel_xf); - lastDisplacement=displacement; - return true; - -} - -void CarWheel::set_type_drive(bool p_enable) { - - type_drive=p_enable; -} - -bool CarWheel::is_type_drive() const { - - return type_drive; -} - -void CarWheel::set_type_steer(bool p_enable) { - - type_steer=p_enable; -} - -bool CarWheel::is_type_steer() const { - - return type_steer; -} - - -void CarWheel::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_side_friction","friction"),&CarWheel::set_side_friction); - ObjectTypeDB::bind_method(_MD("set_forward_friction","friction"),&CarWheel::set_forward_friction); - ObjectTypeDB::bind_method(_MD("set_travel","distance"),&CarWheel::set_travel); - ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CarWheel::set_radius); - ObjectTypeDB::bind_method(_MD("set_resting_frac","frac"),&CarWheel::set_resting_frac); - ObjectTypeDB::bind_method(_MD("set_damping_frac","frac"),&CarWheel::set_damping_frac); - ObjectTypeDB::bind_method(_MD("set_num_rays","amount"),&CarWheel::set_num_rays); - - ObjectTypeDB::bind_method(_MD("get_side_friction"),&CarWheel::get_side_friction); - ObjectTypeDB::bind_method(_MD("get_forward_friction"),&CarWheel::get_forward_friction); - ObjectTypeDB::bind_method(_MD("get_travel"),&CarWheel::get_travel); - ObjectTypeDB::bind_method(_MD("get_radius"),&CarWheel::get_radius); - ObjectTypeDB::bind_method(_MD("get_resting_frac"),&CarWheel::get_resting_frac); - ObjectTypeDB::bind_method(_MD("get_damping_frac"),&CarWheel::get_damping_frac); - ObjectTypeDB::bind_method(_MD("get_num_rays"),&CarWheel::get_num_rays); - - ObjectTypeDB::bind_method(_MD("set_type_drive","enable"),&CarWheel::set_type_drive); - ObjectTypeDB::bind_method(_MD("is_type_drive"),&CarWheel::is_type_drive); - - ObjectTypeDB::bind_method(_MD("set_type_steer","enable"),&CarWheel::set_type_steer); - ObjectTypeDB::bind_method(_MD("is_type_steer"),&CarWheel::is_type_steer); - - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"type/drive"),_SCS("set_type_drive"),_SCS("is_type_drive")); - ADD_PROPERTY( PropertyInfo(Variant::BOOL,"type/steer"),_SCS("set_type_steer"),_SCS("is_type_steer")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/side_friction",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_side_friction"),_SCS("get_side_friction")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/forward_friction",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_forward_friction"),_SCS("get_forward_friction")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/travel",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_travel"),_SCS("get_travel")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/radius",PROPERTY_HINT_RANGE,"0.01,1024,0.01"),_SCS("set_radius"),_SCS("get_radius")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/resting_frac",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_resting_frac"),_SCS("get_resting_frac")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/damping_frac",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_damping_frac"),_SCS("get_damping_frac")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/num_rays",PROPERTY_HINT_RANGE,"1,32,1"),_SCS("set_num_rays"),_SCS("get_num_rays")); - -} - -CarWheel::CarWheel() { - - side_friction=4.7; - forward_friction=5.0; - travel=0.2; - radius=0.4; - resting_frac=0.45; - damping_frac=0.3; - num_rays=1; - - angVel = 0.0f; - steerAngle = 0.0f; - torque = 0.0f; - driveTorque = 0.0f; - axisAngle = 0.0f; - upSpeed = 0.0f; - locked = false; - lastDisplacement = 0.0f; - lastOnFloor = false; - angVelForGrip = 0.0f; - angVelForGrip=0; - - type_drive=false; - type_steer=false; - -} - -/// - - -void CarBody::set_max_steer_angle(real_t p_angle) { - - max_steer_angle=p_angle; -} -void CarBody::set_steer_rate(real_t p_rate) { - - steer_rate=p_rate; -} -void CarBody::set_drive_torque(real_t p_torque) { - - drive_torque=p_torque; -} - -real_t CarBody::get_max_steer_angle() const{ - - return max_steer_angle; -} -real_t CarBody::get_steer_rate() const{ - - return steer_rate; -} -real_t CarBody::get_drive_torque() const{ - - return drive_torque; -} - - -void CarBody::set_target_steering(float p_steering) { - - target_steering=p_steering; -} - -void CarBody::set_target_accelerate(float p_accelerate) { - target_accelerate=p_accelerate; -} - -void CarBody::set_hand_brake(float p_amont) { - - hand_brake=p_amont; -} - -real_t CarBody::get_target_steering() const { - - return target_steering; -} -real_t CarBody::get_target_accelerate() const { - - return target_accelerate; -} -real_t CarBody::get_hand_brake() const { - - return hand_brake; -} - - -void CarBody::_direct_state_changed(Object *p_state) { - - PhysicsDirectBodyState *state=p_state->cast_to<PhysicsDirectBodyState>(); - - float dt = state->get_step(); - AABB aabb; - int drive_total=0; - for(int i=0;i<wheels.size();i++) { - CarWheel *w=wheels[i]; - if (i==0) { - aabb.pos=w->local_xform.origin; - } else { - aabb.expand_to(w->local_xform.origin); - } - if (w->type_drive) - drive_total++; - - } - // control inputs - float deltaAccelerate = dt * 4.0f; - - float dAccelerate = target_accelerate - accelerate; - dAccelerate = CLAMP(dAccelerate, -deltaAccelerate, deltaAccelerate); - accelerate += dAccelerate; - - float deltaSteering = dt * steer_rate; - float dSteering = target_steering - steering; - dSteering = CLAMP(dSteering, -deltaSteering, deltaSteering); - steering += dSteering; - - // apply these inputs - float maxTorque = drive_torque; - - float torque_div = drive_total/2; - if (torque_div>0) - maxTorque/=torque_div; - - - float alpha = ABS(max_steer_angle * steering); - float angleSgn = steering > 0.0f ? 1.0f : -1.0f; - - int wheels_on_floor=0; - - for(int i=0;i<wheels.size();i++) { - - CarWheel *w=wheels[i]; - if (w->type_drive) - w->driveTorque+=maxTorque * accelerate; - w->locked = !w->type_steer && (hand_brake > 0.5f); - - if (w->type_steer) { - //steering - - bool inner = (steering > 0 && w->local_xform.origin.x > 0) || (steering < 0 && w->local_xform.origin.x < 0); - - if (inner || alpha==0.0) { - - w->steerAngle = (angleSgn * alpha); - } else { - float dx = aabb.size.z; - float dy = aabb.size.x; - - float beta = Math::atan2(dy, dx + (dy / (float)Math::tan(Math::deg2rad(alpha)))); - beta = Math::rad2deg(beta); - w->steerAngle = (angleSgn * beta); - - } - } - - if (w->add_forces(state)) - wheels_on_floor++; - w->update(dt); - - - } - - print_line("onfloor: "+itos(wheels_on_floor)); - - - set_ignore_transform_notification(true); - set_global_transform(state->get_transform()); - linear_velocity=state->get_linear_velocity(); - angular_velocity=state->get_angular_velocity(); - //active=!state->is_sleeping(); - //if (get_script_instance()) - // get_script_instance()->call("_integrate_forces",state); - set_ignore_transform_notification(false); - - -} - -void CarBody::set_mass(real_t p_mass) { - - mass=p_mass; - PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_MASS,mass); -} - -real_t CarBody::get_mass() const{ - - return mass; -} - - -void CarBody::set_friction(real_t p_friction) { - - friction=p_friction; - PhysicsServer::get_singleton()->body_set_param(get_rid(),PhysicsServer::BODY_PARAM_FRICTION,friction); -} - -real_t CarBody::get_friction() const{ - - return friction; -} - - -void CarBody::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_max_steer_angle","value"),&CarBody::set_max_steer_angle); - ObjectTypeDB::bind_method(_MD("set_steer_rate","rate"),&CarBody::set_steer_rate); - ObjectTypeDB::bind_method(_MD("set_drive_torque","value"),&CarBody::set_drive_torque); - - ObjectTypeDB::bind_method(_MD("get_max_steer_angle"),&CarBody::get_max_steer_angle); - ObjectTypeDB::bind_method(_MD("get_steer_rate"),&CarBody::get_steer_rate); - ObjectTypeDB::bind_method(_MD("get_drive_torque"),&CarBody::get_drive_torque); - - ObjectTypeDB::bind_method(_MD("set_target_steering","amount"),&CarBody::set_target_steering); - ObjectTypeDB::bind_method(_MD("set_target_accelerate","amount"),&CarBody::set_target_accelerate); - ObjectTypeDB::bind_method(_MD("set_hand_brake","amount"),&CarBody::set_hand_brake); - - ObjectTypeDB::bind_method(_MD("get_target_steering"),&CarBody::get_target_steering); - ObjectTypeDB::bind_method(_MD("get_target_accelerate"),&CarBody::get_target_accelerate); - ObjectTypeDB::bind_method(_MD("get_hand_brake"),&CarBody::get_hand_brake); - - ObjectTypeDB::bind_method(_MD("set_mass","mass"),&CarBody::set_mass); - ObjectTypeDB::bind_method(_MD("get_mass"),&CarBody::get_mass); - - ObjectTypeDB::bind_method(_MD("set_friction","friction"),&CarBody::set_friction); - ObjectTypeDB::bind_method(_MD("get_friction"),&CarBody::get_friction); - - ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&CarBody::_direct_state_changed); - - ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); - - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/max_steer_angle",PROPERTY_HINT_RANGE,"1,90,1"),_SCS("set_max_steer_angle"),_SCS("get_max_steer_angle")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/drive_torque",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_drive_torque"),_SCS("get_drive_torque")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"config/steer_rate",PROPERTY_HINT_RANGE,"0.01,64,0.01"),_SCS("set_steer_rate"),_SCS("get_steer_rate")); - - ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/target_steering",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_target_steering"),_SCS("get_target_steering")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/target_accelerate",PROPERTY_HINT_RANGE,"-1,1,0.01"),_SCS("set_target_accelerate"),_SCS("get_target_accelerate")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"drive/hand_brake",PROPERTY_HINT_RANGE,"0,1,0.01"),_SCS("set_hand_brake"),_SCS("get_hand_brake")); - -} - -CarBody::CarBody() : PhysicsBody(PhysicsServer::BODY_MODE_RIGID) { - - forward_drive=true; - backward_drive=true; - max_steer_angle=30; - steer_rate=1; - drive_torque=520; - - target_steering=0; - target_accelerate=0; - hand_brake=0; - - steering=0; - accelerate=0; - - mass=1; - friction=1; - - ccd=false; -// can_sleep=true; - - - - - exclude.insert(get_rid()); - PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(),this,"_direct_state_changed"); - - -} diff --git a/scene/3d/car_body.h b/scene/3d/car_body.h deleted file mode 100644 index 87eb047bcf..0000000000 --- a/scene/3d/car_body.h +++ /dev/null @@ -1,170 +0,0 @@ -/*************************************************************************/ -/* car_body.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef CAR_BODY_H -#define CAR_BODY_H - -#include "scene/3d/physics_body.h" - - -class CarBody; - -class CarWheel : public Spatial { - - OBJ_TYPE(CarWheel,Spatial); - -friend class CarBody; - real_t side_friction; - real_t forward_friction; - real_t travel; - real_t radius; - real_t resting_frac; - real_t damping_frac; - int num_rays; - Transform local_xform; - - CarBody *body; - - float angVel; - float steerAngle; - float torque; - float driveTorque; - float axisAngle; - float upSpeed; // speed relative to the car - bool locked; - // last frame stuff - float lastDisplacement; - float angVelForGrip; - bool lastOnFloor; - - bool type_drive; - bool type_steer; - - -protected: - void update(real_t dt); - bool add_forces(PhysicsDirectBodyState *s); - void _notification(int p_what); - static void _bind_methods(); - -public: - - void set_side_friction(real_t p_friction); - void set_forward_friction(real_t p_friction); - void set_travel(real_t p_travel); - void set_radius(real_t p_radius); - void set_resting_frac(real_t p_frac); - void set_damping_frac(real_t p_frac); - void set_num_rays(real_t p_rays); - - real_t get_side_friction() const; - real_t get_forward_friction() const; - real_t get_travel() const; - real_t get_radius() const; - real_t get_resting_frac() const; - real_t get_damping_frac() const; - int get_num_rays() const; - - void set_type_drive(bool p_enable); - bool is_type_drive() const; - - void set_type_steer(bool p_enable); - bool is_type_steer() const; - - CarWheel(); - -}; - - - -class CarBody : public PhysicsBody { - - OBJ_TYPE(CarBody,PhysicsBody); - - real_t mass; - real_t friction; - - Vector3 linear_velocity; - Vector3 angular_velocity; - bool ccd; - - real_t max_steer_angle; - real_t steer_rate; - int wheel_num_rays; - real_t drive_torque; - -// control stuff - real_t target_steering; - real_t target_accelerate; - - bool forward_drive; - bool backward_drive; - - real_t steering; - real_t accelerate; - real_t hand_brake; - Set<RID> exclude; - - -friend class CarWheel; - Vector<CarWheel*> wheels; - - static void _bind_methods(); - - void _direct_state_changed(Object *p_state); -public: - - - void set_mass(real_t p_mass); - real_t get_mass() const; - - void set_friction(real_t p_friction); - real_t get_friction() const; - - void set_max_steer_angle(real_t p_angle); - void set_steer_rate(real_t p_rate); - void set_drive_torque(real_t p_torque); - - real_t get_max_steer_angle() const; - real_t get_steer_rate() const; - real_t get_drive_torque() const; - - - void set_target_steering(float p_steering); - void set_target_accelerate(float p_accelerate); - void set_hand_brake(float p_amont); - - real_t get_target_steering() const; - real_t get_target_accelerate() const; - real_t get_hand_brake() const; - - - CarBody(); -}; - -#endif // CAR_BODY_H diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp index 06564f5c49..9c388a2883 100644 --- a/scene/3d/collision_object.cpp +++ b/scene/3d/collision_object.cpp @@ -47,14 +47,20 @@ void CollisionObject::_notification(int p_what) { case NOTIFICATION_ENTER_WORLD: { + if (area) + PhysicsServer::get_singleton()->area_set_transform(rid,get_global_transform()); + else + PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); + RID space = get_world()->get_space(); if (area) { PhysicsServer::get_singleton()->area_set_space(rid,space); } else PhysicsServer::get_singleton()->body_set_space(rid,space); + _update_pickable(); //get space - } + }; case NOTIFICATION_TRANSFORM_CHANGED: { @@ -64,6 +70,11 @@ void CollisionObject::_notification(int p_what) { PhysicsServer::get_singleton()->body_set_state(rid,PhysicsServer::BODY_STATE_TRANSFORM,get_global_transform()); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + + _update_pickable(); + + } break; case NOTIFICATION_EXIT_WORLD: { if (area) { @@ -91,11 +102,11 @@ void CollisionObject::_update_shapes() { continue; if (area) PhysicsServer::get_singleton()->area_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform); - else { + else { PhysicsServer::get_singleton()->body_add_shape(rid,shapes[i].shape->get_rid(),shapes[i].xform); - if (shapes[i].trigger) - PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger); - } + if (shapes[i].trigger) + PhysicsServer::get_singleton()->body_set_shape_as_trigger(rid,i,shapes[i].trigger); + } } } @@ -154,24 +165,24 @@ bool CollisionObject::_get(const StringName& p_name,Variant &r_ret) const { void CollisionObject::_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) ); + 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)+"/"; - p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape",PROPERTY_USAGE_NOEDITOR) ); - p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); - p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR) ); + p_list->push_back( PropertyInfo(Variant::OBJECT,path+"shape",PROPERTY_HINT_RESOURCE_TYPE,"Shape",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + p_list->push_back( PropertyInfo(Variant::TRANSFORM,path+"transform",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); + p_list->push_back( PropertyInfo(Variant::BOOL,path+"trigger",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_NO_INSTANCE_STATE) ); } } -void CollisionObject::_input_event(const InputEvent& p_input_event,const Vector3& p_pos, const Vector3& p_normal, int p_shape) { +void CollisionObject::_input_event(Node *p_camera, const InputEvent& p_input_event, const Vector3& p_pos, const Vector3& p_normal, int p_shape) { if (get_script_instance()) { - get_script_instance()->call(SceneStringNames::get_singleton()->_input_event,p_input_event,p_pos,p_normal,p_shape); + get_script_instance()->call(SceneStringNames::get_singleton()->_input_event,p_camera,p_input_event,p_pos,p_normal,p_shape); } - emit_signal(SceneStringNames::get_singleton()->input_event,p_input_event,p_pos,p_normal,p_shape); + emit_signal(SceneStringNames::get_singleton()->input_event,p_camera,p_input_event,p_pos,p_normal,p_shape); } void CollisionObject::_mouse_enter() { @@ -192,6 +203,28 @@ void CollisionObject::_mouse_exit() { } +void CollisionObject::_update_pickable() { + if (!is_inside_tree()) + return; + bool pickable = ray_pickable && is_inside_tree() && is_visible(); + if (area) + PhysicsServer::get_singleton()->area_set_ray_pickable(rid,pickable); + else + PhysicsServer::get_singleton()->body_set_ray_pickable(rid,pickable); +} + +void CollisionObject::set_ray_pickable(bool p_ray_pickable) { + + ray_pickable=p_ray_pickable; + _update_pickable(); + +} + +bool CollisionObject::is_ray_pickable() const { + + return ray_pickable; +} + void CollisionObject::_bind_methods() { @@ -206,15 +239,18 @@ void CollisionObject::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_shape_transform","shape_idx"),&CollisionObject::get_shape_transform); ObjectTypeDB::bind_method(_MD("remove_shape","shape_idx"),&CollisionObject::remove_shape); ObjectTypeDB::bind_method(_MD("clear_shapes"),&CollisionObject::clear_shapes); + ObjectTypeDB::bind_method(_MD("set_ray_pickable","ray_pickable"),&CollisionObject::set_ray_pickable); + ObjectTypeDB::bind_method(_MD("is_ray_pickable"),&CollisionObject::is_ray_pickable); ObjectTypeDB::bind_method(_MD("set_capture_input_on_drag","enable"),&CollisionObject::set_capture_input_on_drag); ObjectTypeDB::bind_method(_MD("get_capture_input_on_drag"),&CollisionObject::get_capture_input_on_drag); ObjectTypeDB::bind_method(_MD("get_rid"),&CollisionObject::get_rid); - BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx"))); + BIND_VMETHOD( MethodInfo("_input_event",PropertyInfo(Variant::OBJECT,"camera"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx"))); - ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx"))); + ADD_SIGNAL( MethodInfo("input_event",PropertyInfo(Variant::OBJECT,"camera"),PropertyInfo(Variant::INPUT_EVENT,"event"),PropertyInfo(Variant::VECTOR3,"click_pos"),PropertyInfo(Variant::VECTOR3,"click_normal"),PropertyInfo(Variant::INT,"shape_idx"))); ADD_SIGNAL( MethodInfo("mouse_enter")); ADD_SIGNAL( MethodInfo("mouse_exit")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"input/ray_pickable"),_SCS("set_ray_pickable"),_SCS("is_ray_pickable")); ADD_PROPERTY(PropertyInfo(Variant::BOOL,"input/capture_on_drag"),_SCS("set_capture_input_on_drag"),_SCS("get_capture_input_on_drag")); } @@ -296,6 +332,8 @@ CollisionObject::CollisionObject(RID p_rid, bool p_area) { rid=p_rid; area=p_area; + capture_input_on_drag=false; + ray_pickable=true; if (p_area) { PhysicsServer::get_singleton()->area_attach_object_instance_ID(rid,get_instance_ID()); } else { @@ -321,6 +359,7 @@ CollisionObject::CollisionObject() { capture_input_on_drag=false; + ray_pickable=true; //owner= diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h index afd73aa9cc..eafce2c82c 100644 --- a/scene/3d/collision_object.h +++ b/scene/3d/collision_object.h @@ -51,9 +51,10 @@ class CollisionObject : public Spatial { }; bool capture_input_on_drag; - + bool ray_pickable; Vector<ShapeData> shapes; + void _update_pickable(); void _update_shapes(); friend class CollisionShape; @@ -69,7 +70,7 @@ protected: void _get_property_list( List<PropertyInfo> *p_list) const; static void _bind_methods(); friend class Viewport; - virtual void _input_event(const InputEvent& p_input_event,const Vector3& p_pos, const Vector3& p_normal, int p_shape); + virtual void _input_event(Node* p_camera,const InputEvent& p_input_event,const Vector3& p_pos, const Vector3& p_normal, int p_shape); virtual void _mouse_enter(); virtual void _mouse_exit(); @@ -87,9 +88,13 @@ public: void set_shape_as_trigger(int p_shape_idx, bool p_trigger); bool is_shape_set_as_trigger(int p_shape_idx) const; + void set_ray_pickable(bool p_ray_pickable); + bool is_ray_pickable() const; + void set_capture_input_on_drag(bool p_capture); bool get_capture_input_on_drag() const; + _FORCE_INLINE_ RID get_rid() const { return rid; } CollisionObject(); diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp index 5a613f360a..4ab1a1a1ab 100644 --- a/scene/3d/collision_polygon.cpp +++ b/scene/3d/collision_polygon.cpp @@ -86,7 +86,7 @@ void CollisionPolygon::_notification(int p_what) { switch(p_what) { case NOTIFICATION_TRANSFORM_CHANGED: { - if (!is_inside_scene()) + if (!is_inside_tree()) break; _update_parent(); diff --git a/scene/3d/editable_shape.cpp b/scene/3d/editable_shape.cpp deleted file mode 100644 index ab3f832028..0000000000 --- a/scene/3d/editable_shape.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/*************************************************************************/ -/* editable_shape.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "editable_shape.h" - - -void EditableShape::_notification(int p_what) { - - - -} - - -void EditableShape::set_bsp_tree(const BSP_Tree& p_bsp) { - - bsp=p_bsp; -} - -void EditableShape::set_shape(const Ref<Shape>& p_shape) { - - shape=p_shape; -} - - - -EditableShape::EditableShape() -{ -} - - - -///////////////////////// - - -void EditableSphere::set_radius(float p_radius) { - - radius=p_radius; - update_gizmo(); - _change_notify("params/radius"); -} - - -float EditableSphere::get_radius() const{ - - return radius; -} - - -void EditableSphere::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_radius","radius"),&EditableSphere::set_radius); - ObjectTypeDB::bind_method(_MD("get_radius"),&EditableSphere::get_radius); - - ADD_PROPERTY( PropertyInfo(Variant::REAL,"params/radius",PROPERTY_HINT_EXP_RANGE,"0.001,16384,0.001"),_SCS("set_radius"),_SCS("get_radius")); -} - -EditableSphere::EditableSphere() { - - radius=1.0; -} diff --git a/scene/3d/editable_shape.h b/scene/3d/editable_shape.h deleted file mode 100644 index 9accea575c..0000000000 --- a/scene/3d/editable_shape.h +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************/ -/* editable_shape.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef EDITABLE_SHAPE_H -#define EDITABLE_SHAPE_H - -#include "scene/3d/spatial.h" -#include "scene/resources/shape.h" - -class EditableShape : public Spatial { - - OBJ_TYPE(EditableShape,Spatial); - - //can hold either of those - BSP_Tree bsp; - Ref<Shape> shape; - - void _update_parent(); -protected: - - void _notification(int p_what); - - void set_bsp_tree(const BSP_Tree& p_bsp); - void set_shape(const Ref<Shape>& p_shape); -public: - EditableShape(); -}; - - -class EditableSphere : public EditableShape { - - OBJ_TYPE( EditableSphere, EditableShape ); - - - float radius; -protected: - - static void _bind_methods(); -public: - - void set_radius(float p_radius); - float get_radius() const; - - EditableSphere(); -}; - - -#endif // EDITABLE_SHAPE_H diff --git a/scene/3d/follow_camera.cpp b/scene/3d/follow_camera.cpp deleted file mode 100644 index e7ced6c2ba..0000000000 --- a/scene/3d/follow_camera.cpp +++ /dev/null @@ -1,778 +0,0 @@ -/*************************************************************************/ -/* follow_camera.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "follow_camera.h" - - -#include "physics_body.h" -#include "scene/resources/surface_tool.h" - -void FollowCamera::_set_initial_orbit(const Vector2& p_orbit) { - - initial_orbit=p_orbit; - set_orbit(p_orbit); -} - - - -void FollowCamera::_clear_queries() { - - if (!queries_active) - return; -#if 0 - for(int i=0;i<3;i++) - PhysicsServer::get_singleton()->query_clear(clip_ray[i].query); -#endif - queries_active=false; - -} - -void FollowCamera::_compute_camera() { - - // update the transform with the next proposed transform (camera is 1 logic frame delayed) - - /* - float time = get_root_node()->get_frame_time(); - Vector3 oldp = accepted.get_origin(); - Vector3 newp = proposed.get_origin(); - - float frame_dist = time * - if (oldp.distance_to(newp) > - */ - - float time = get_process_delta_time(); - bool noblend=false; - - if (clip) { - - if ((clip_ray[0].clipped==clip_ray[2].clipped || fullclip) && clip_ray[1].clipped) { - //all have been clipped - proposed_pos=clip_ray[1].clip_pos-extraclip*(proposed_pos-target_pos).normalized(); - if (clip_ray[0].clipped) - fullclip=true; - noblend=true; - - - } else { - - - //Vector3 rel=follow_pos-target_pos; - - if (clip_ray[0].clipped && !clip_ray[2].clipped) { - - float distance = target_pos.distance_to(clip_ray[0].clip_pos); - real_t amount = 1.0-(distance/clip_len); - amount = CLAMP(amount,0,1)*autoturn_speed*time; - if (clip_ray[1].clipped) - amount*=2.0; - //rotate_rel=Matrix3(Vector3(0,1,0),amount).xform(rel); - rotate_orbit(Vector2(0,amount)); - - } else if (clip_ray[2].clipped && !clip_ray[0].clipped) { - - float distance = target_pos.distance_to(clip_ray[2].clip_pos); - real_t amount = 1.0-(distance/clip_len); - amount = CLAMP(amount,0,1)*autoturn_speed*time; - if (clip_ray[1].clipped) - amount*=2.0; - rotate_orbit(Vector2(0,-amount)); - } - - fullclip=false; - - } - } - - - Vector3 base_pos = get_global_transform().origin; - Vector3 pull_from = base_pos; - pull_from.y+=height; // height compensate - - - - Vector3 camera_target; - if (use_lookat_target) { - - camera_target = lookat_target; - } else { - camera_target = base_pos; - }; - - Transform proposed; - proposed.set_look_at(proposed_pos,camera_target,up_vector); - proposed = proposed * Transform(Matrix3(Vector3(1,0,0),Math::deg2rad(inclination)),Vector3()); //inclination - - - accepted=proposed; - if (smooth && !noblend) { - - - Vector3 vec1 = accepted.origin; - Vector3 vec2 = final.origin; - final.origin = vec2.linear_interpolate(vec1, MIN(1,smooth_pos_ratio * time));; - - Quat q1 = accepted.basis; - Quat q2 = final.basis; - final.basis = q2.slerp(q1, MIN(1,smooth_rot_ratio * time)); - - } else { - final=accepted; - } - - _update_camera(); - - // calculate the next proposed transform - - - Vector3 new_pos; - - { /*follow code*/ - - - - /* calculate some variables */ - - Vector3 rel = follow_pos - pull_from; - - float l = rel.length(); - Vector3 rel_n = (l > 0) ? (rel/l) : Vector3(); - float ang = Math::acos(rel_n.dot( Vector3(0,1,0) )); - - Vector3 tangent = rel_n; - tangent.y=0; // get rid of y - if (tangent.length_squared() < CMP_EPSILON2) - tangent=Vector3(0,0,1); // use Z as tangent if rel is parallel to y - else - tangent.normalize(); - - /* now start applying the rules */ - - //clip distance - if (l > max_distance) - l=max_distance; - if (l < min_distance) - l=min_distance; - - //fix angle - - float ang_min = Math_PI * 0.5 + Math::deg2rad(min_orbit_x); - float ang_max = Math_PI * 0.5 + Math::deg2rad(max_orbit_x); - - if (ang<ang_min) - ang=ang_min; - if (ang>ang_max) - ang=ang_max; - - /* finally, rebuild the validated camera position */ - - new_pos=Vector3(0,Math::cos(ang),0); - new_pos+=tangent*Math::sin(ang); - new_pos*=l; - new_pos+=pull_from; - follow_pos=new_pos; - - } - - proposed_pos=new_pos; - - Vector3 rel = new_pos-camera_target; - - - if (clip) { - - Vector<RID> exclude; - exclude.push_back(target_body); - - for(int i=0;i<3;i++) { - - clip_ray[i].clipped=false; - clip_ray[i].clip_pos=Vector3(); - clip_ray[i].cast_pos=camera_target; - - Vector3 cast_to = camera_target+Matrix3(Vector3(0,1,0),Math::deg2rad(autoturn_tolerance*(i-1.0))).xform(rel); - - - if (i!=1) { - - Vector3 side = rel.cross(Vector3(0,1,0)).normalized()*(i-1.0); - clip_ray[i].cast_pos+side*target_width+rel.normalized()*target_width; - - Vector3 d = -rel; - d.rotate(Vector3(0,1,0),Math::deg2rad(get_fov())*(i-1.0)); - Plane p(new_pos,new_pos+d,new_pos+Vector3(0,1,0)); //fov clipping plane, build a face and use it as plane, facing doesn't matter - Vector3 intersect; - if (p.intersects_segment(clip_ray[i].cast_pos,cast_to,&intersect)) - cast_to=intersect; - - } else { - - cast_to+=rel.normalized()*extraclip; - } - - // PhysicsServer::get_singleton()->query_intersection(clip_ray[i].query,get_world()->get_space(),exclude); - // PhysicsServer::get_singleton()->query_intersection_segment(clip_ray[i].query,clip_ray[i].cast_pos,cast_to); - - - - - } - - queries_active=true; - } else { - - _clear_queries(); - } - target_pos=camera_target; - clip_len=rel.length(); - -} - -void FollowCamera::set_use_lookat_target(bool p_use, const Vector3 &p_lookat) { - - use_lookat_target = p_use; - lookat_target = p_lookat; -}; - - -void FollowCamera::_notification(int p_what) { - - switch(p_what) { - - case NOTIFICATION_PROCESS: { - - - _compute_camera(); - } break; - - case NOTIFICATION_ENTER_WORLD: { - - set_orbit(orbit); - set_distance(distance); - - accepted=final=get_global_transform(); - proposed_pos=accepted.origin; - - target_body = RID(); -/* - Node* parent = get_parent(); - while (parent) { - PhysicsBody* p = parent->cast_to<PhysicsBody>(); - if (p) { - target_body = p->get_body(); - break; - }; - parent = parent->get_parent(); - }; -*/ - set_process(true); - - } break; - case NOTIFICATION_TRANSFORM_CHANGED: { - - } break; - case NOTIFICATION_EXIT_WORLD: { - - distance=get_distance(); - orbit=get_orbit(); - _clear_queries(); - - } break; - case NOTIFICATION_BECAME_CURRENT: { - - set_process(true); - } break; - case NOTIFICATION_LOST_CURRENT: { - - set_process(false); - _clear_queries(); - - } break; - } - -} - - - -void FollowCamera::set_orbit(const Vector2& p_orbit) { - - orbit=p_orbit; - - if(is_inside_scene()) { - - Vector3 char_pos = get_global_transform().origin; - char_pos.y+=height; - float d = char_pos.distance_to(follow_pos); - - Matrix3 m; - m.rotate(Vector3(0,1,0),orbit.y); - m.rotate(Vector3(1,0,0),orbit.x); - - follow_pos=char_pos + m.get_axis(2) * d; - - } - - update_gizmo(); - -} -void FollowCamera::set_orbit_x(float p_x) { - - orbit.x=p_x; - if(is_inside_scene()) - set_orbit(Vector2( p_x, get_orbit().y )); -} -void FollowCamera::set_orbit_y(float p_y) { - - - orbit.y=p_y; - if(is_inside_scene()) - set_orbit(Vector2( get_orbit().x, p_y )); - -} -Vector2 FollowCamera::get_orbit() const { - - - if (is_inside_scene()) { - - Vector3 char_pos = get_global_transform().origin; - char_pos.y+=height; - Vector3 rel = (follow_pos - char_pos).normalized(); - Vector2 ret_orbit; - ret_orbit.x = Math::acos( Vector3(0,1,0).dot( rel ) ) - Math_PI * 0.5; - ret_orbit.y = Math::atan2(rel.x,rel.z); - return ret_orbit; - } - return orbit; -} - -void FollowCamera::rotate_orbit(const Vector2& p_relative) { - - if (is_inside_scene()) { - - Matrix3 m; - m.rotate(Vector3(0,1,0),Math::deg2rad(p_relative.y)); - m.rotate(Vector3(1,0,0),Math::deg2rad(p_relative.x)); - - Vector3 char_pos = get_global_transform().origin; - char_pos.y+=height; - Vector3 rel = (follow_pos - char_pos); - rel = m.xform(rel); - follow_pos=char_pos+rel; - - } - - orbit+=p_relative; - update_gizmo(); -} - -void FollowCamera::set_height(float p_height) { - - - height=p_height; - update_gizmo(); -} - -float FollowCamera::get_height() const { - - return height; - -} - -void FollowCamera::set_max_orbit_x(float p_max) { - - max_orbit_x=p_max; - update_gizmo(); -} - -float FollowCamera::get_max_orbit_x() const { - - return max_orbit_x; -} - -void FollowCamera::set_min_orbit_x(float p_min) { - - min_orbit_x=p_min; - update_gizmo(); -} - -float FollowCamera::get_min_orbit_x() const { - - return min_orbit_x; -} - -float FollowCamera::get_min_distance() const { - - return min_distance; -} -float FollowCamera::get_max_distance() const { - - return max_distance; -} - -void FollowCamera::set_min_distance(float p_min) { - - min_distance=p_min; - update_gizmo(); -} - -void FollowCamera::set_max_distance(float p_max) { - - max_distance = p_max; - update_gizmo(); -} - - -void FollowCamera::set_distance(float p_distance) { - - if (is_inside_scene()) { - - Vector3 char_pos = get_global_transform().origin; - char_pos.y+=height; - Vector3 rel = (follow_pos - char_pos).normalized(); - rel*=p_distance; - follow_pos=char_pos+rel; - - } - - distance=p_distance; -} - -float FollowCamera::get_distance() const { - - if (is_inside_scene()) { - - Vector3 char_pos = get_global_transform().origin; - char_pos.y+=height; - return (follow_pos - char_pos).length(); - - } - - return distance; -} - -void FollowCamera::set_clip(bool p_enabled) { - - - clip=p_enabled; - - if (!p_enabled) - _clear_queries(); -} - -bool FollowCamera::has_clip() const { - - return clip; - -} - - -void FollowCamera::set_autoturn(bool p_enabled) { - - - autoturn=p_enabled; -} - -bool FollowCamera::has_autoturn() const { - - return autoturn; - -} - -void FollowCamera::set_autoturn_tolerance(float p_degrees) { - - - autoturn_tolerance=p_degrees; -} -float FollowCamera::get_autoturn_tolerance() const { - - - return autoturn_tolerance; -} - -void FollowCamera::set_inclination(float p_degrees) { - - - inclination=p_degrees; -} -float FollowCamera::get_inclination() const { - - - return inclination; -} - - -void FollowCamera::set_autoturn_speed(float p_speed) { - - - autoturn_speed=p_speed; -} - -float FollowCamera::get_autoturn_speed() const { - - return autoturn_speed; - -} - - -RES FollowCamera::_get_gizmo_geometry() const { - - Ref<SurfaceTool> surface_tool( memnew( SurfaceTool )); - - Ref<FixedMaterial> mat( memnew( FixedMaterial )); - - mat->set_parameter( FixedMaterial::PARAM_DIFFUSE,Color(1.0,0.5,1.0,0.3) ); - mat->set_line_width(4); - mat->set_flag(Material::FLAG_DOUBLE_SIDED,true); - mat->set_flag(Material::FLAG_UNSHADED,true); -// mat->set_hint(Material::HINT_NO_DEPTH_DRAW,true); - - surface_tool->begin(Mesh::PRIMITIVE_LINES); - surface_tool->set_material(mat); - - - int steps=16; - - Vector3 base_up = Matrix3(Vector3(1,0,0),Math::deg2rad(max_orbit_x)).get_axis(2); - Vector3 base_down = Matrix3(Vector3(1,0,0),Math::deg2rad(min_orbit_x)).get_axis(2); - - Vector3 ofs(0,height,0); - - for(int i=0;i<steps;i++) { - - - Matrix3 rot(Vector3(0,1,0),Math_PI*2*float(i)/steps); - Matrix3 rot2(Vector3(0,1,0),Math_PI*2*float(i+1)/steps); - - Vector3 up = rot.xform(base_up); - Vector3 up2 = rot2.xform(base_up); - - Vector3 down = rot.xform(base_down); - Vector3 down2 = rot2.xform(base_down); - - surface_tool->add_vertex(ofs+up*min_distance); - surface_tool->add_vertex(ofs+up*max_distance); - surface_tool->add_vertex(ofs+up*min_distance); - surface_tool->add_vertex(ofs+up2*min_distance); - surface_tool->add_vertex(ofs+up*max_distance); - surface_tool->add_vertex(ofs+up2*max_distance); - - surface_tool->add_vertex(ofs+down*min_distance); - surface_tool->add_vertex(ofs+down*max_distance); - surface_tool->add_vertex(ofs+down*min_distance); - surface_tool->add_vertex(ofs+down2*min_distance); - surface_tool->add_vertex(ofs+down*max_distance); - surface_tool->add_vertex(ofs+down2*max_distance); - - int substeps = 8; - - for(int j=0;j<substeps;j++) { - - Vector3 a = up.linear_interpolate(down,float(j)/substeps).normalized()*max_distance; - Vector3 b = up.linear_interpolate(down,float(j+1)/substeps).normalized()*max_distance; - Vector3 am = up.linear_interpolate(down,float(j)/substeps).normalized()*min_distance; - Vector3 bm = up.linear_interpolate(down,float(j+1)/substeps).normalized()*min_distance; - - surface_tool->add_vertex(ofs+a); - surface_tool->add_vertex(ofs+b); - surface_tool->add_vertex(ofs+am); - surface_tool->add_vertex(ofs+bm); - - } - } - - - return surface_tool->commit(); - - -} - - -void FollowCamera::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("_set_initial_orbit","orbit"),&FollowCamera::_set_initial_orbit); - ObjectTypeDB::bind_method(_MD("set_orbit","orbit"),&FollowCamera::set_orbit); - ObjectTypeDB::bind_method(_MD("get_orbit"),&FollowCamera::get_orbit); - ObjectTypeDB::bind_method(_MD("set_orbit_x","x"),&FollowCamera::set_orbit_x); - ObjectTypeDB::bind_method(_MD("set_orbit_y","y"),&FollowCamera::set_orbit_y); - ObjectTypeDB::bind_method(_MD("set_min_orbit_x","x"),&FollowCamera::set_min_orbit_x); - ObjectTypeDB::bind_method(_MD("get_min_orbit_x"),&FollowCamera::get_min_orbit_x); - ObjectTypeDB::bind_method(_MD("set_max_orbit_x","x"),&FollowCamera::set_max_orbit_x); - ObjectTypeDB::bind_method(_MD("get_max_orbit_x"),&FollowCamera::get_max_orbit_x); - ObjectTypeDB::bind_method(_MD("set_height","height"),&FollowCamera::set_height); - ObjectTypeDB::bind_method(_MD("get_height"),&FollowCamera::get_height); - ObjectTypeDB::bind_method(_MD("set_inclination","inclination"),&FollowCamera::set_inclination); - ObjectTypeDB::bind_method(_MD("get_inclination"),&FollowCamera::get_inclination); - - ObjectTypeDB::bind_method(_MD("rotate_orbit"),&FollowCamera::rotate_orbit); - ObjectTypeDB::bind_method(_MD("set_distance","distance"),&FollowCamera::set_distance); - ObjectTypeDB::bind_method(_MD("get_distance"),&FollowCamera::get_distance); - ObjectTypeDB::bind_method(_MD("set_max_distance","max_distance"),&FollowCamera::set_max_distance); - ObjectTypeDB::bind_method(_MD("get_max_distance"),&FollowCamera::get_max_distance); - ObjectTypeDB::bind_method(_MD("set_min_distance","min_distance"),&FollowCamera::set_min_distance); - ObjectTypeDB::bind_method(_MD("get_min_distance"),&FollowCamera::get_min_distance); - ObjectTypeDB::bind_method(_MD("set_clip","enable"),&FollowCamera::set_clip); - ObjectTypeDB::bind_method(_MD("has_clip"),&FollowCamera::has_clip); - ObjectTypeDB::bind_method(_MD("set_autoturn","enable"),&FollowCamera::set_autoturn); - ObjectTypeDB::bind_method(_MD("has_autoturn"),&FollowCamera::has_autoturn); - ObjectTypeDB::bind_method(_MD("set_autoturn_tolerance","degrees"),&FollowCamera::set_autoturn_tolerance); - ObjectTypeDB::bind_method(_MD("get_autoturn_tolerance"),&FollowCamera::get_autoturn_tolerance); - ObjectTypeDB::bind_method(_MD("set_autoturn_speed","speed"),&FollowCamera::set_autoturn_speed); - ObjectTypeDB::bind_method(_MD("get_autoturn_speed"),&FollowCamera::get_autoturn_speed); - ObjectTypeDB::bind_method(_MD("set_smoothing","enable"),&FollowCamera::set_smoothing); - ObjectTypeDB::bind_method(_MD("has_smoothing"),&FollowCamera::has_smoothing); - ObjectTypeDB::bind_method(_MD("set_rotation_smoothing","amount"),&FollowCamera::set_rotation_smoothing); - ObjectTypeDB::bind_method(_MD("get_rotation_smoothing"),&FollowCamera::get_rotation_smoothing); - ObjectTypeDB::bind_method(_MD("set_translation_smoothing","amount"),&FollowCamera::set_translation_smoothing); - ObjectTypeDB::bind_method(_MD("get_translation_smoothing"),&FollowCamera::get_translation_smoothing); - ObjectTypeDB::bind_method(_MD("set_use_lookat_target","use","lookat"),&FollowCamera::set_use_lookat_target, DEFVAL(Vector3())); - ObjectTypeDB::bind_method(_MD("set_up_vector","vector"),&FollowCamera::set_up_vector); - ObjectTypeDB::bind_method(_MD("get_up_vector"),&FollowCamera::get_up_vector); - - ObjectTypeDB::bind_method(_MD("_ray_collision"),&FollowCamera::_ray_collision); - - ADD_PROPERTY( PropertyInfo( Variant::VECTOR2, "orbit" ), _SCS("_set_initial_orbit"),_SCS("get_orbit") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "height", PROPERTY_HINT_RANGE,"-1024,1024,0.01" ), _SCS("set_height"), _SCS("get_height") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "inclination", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_inclination"), _SCS("get_inclination") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "max_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_max_orbit_x"), _SCS("get_max_orbit_x") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "min_orbit_x", PROPERTY_HINT_RANGE,"-90,90,0.01" ), _SCS("set_min_orbit_x"), _SCS("get_min_orbit_x") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "min_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ), _SCS("set_min_distance"), _SCS("get_min_distance") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "max_distance", PROPERTY_HINT_RANGE,"0,100,0.01" ), _SCS("set_max_distance"), _SCS("get_max_distance") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "distance", PROPERTY_HINT_RANGE,"0.01,1024,0,01"), _SCS("set_distance"), _SCS("get_distance") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "clip"), _SCS("set_clip"), _SCS("has_clip") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "autoturn"), _SCS("set_autoturn"), _SCS("has_autoturn") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "autoturn_tolerance", PROPERTY_HINT_RANGE,"1,90,0.01") , _SCS("set_autoturn_tolerance"), _SCS("get_autoturn_tolerance") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "autoturn_speed", PROPERTY_HINT_RANGE,"1,90,0.01"), _SCS("set_autoturn_speed"), _SCS("get_autoturn_speed") ); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "smoothing"), _SCS("set_smoothing"), _SCS("has_smoothing") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "translation_smooth", PROPERTY_HINT_RANGE,"0.01,128,0.01"), _SCS("set_translation_smoothing"), _SCS("get_translation_smoothing") ); - ADD_PROPERTY( PropertyInfo( Variant::REAL, "rotation_smooth", PROPERTY_HINT_RANGE,"0.01,128,0.01"), _SCS("set_rotation_smoothing"), _SCS("get_rotation_smoothing") ); - - -} - -void FollowCamera::_ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx) { - - clip_ray[p_idx].clip_pos=p_point; - clip_ray[p_idx].clipped=true; - -}; - -Transform FollowCamera::get_camera_transform() const { - - return final; -} - -void FollowCamera::set_smoothing(bool p_enable) { - - smooth=p_enable; -} - -bool FollowCamera::has_smoothing() const { - - return smooth; -} - -void FollowCamera::set_translation_smoothing(float p_amount) { - - smooth_pos_ratio=p_amount; -} -float FollowCamera::get_translation_smoothing() const { - - return smooth_pos_ratio; -} - -void FollowCamera::set_rotation_smoothing(float p_amount) { - - smooth_rot_ratio=p_amount; - -} - -void FollowCamera::set_up_vector(const Vector3& p_up) { - - up_vector=p_up; -} - -Vector3 FollowCamera::get_up_vector() const{ - - return up_vector; -} - -float FollowCamera::get_rotation_smoothing() const { - - return smooth_pos_ratio; - -} - - -FollowCamera::FollowCamera() { - - - height=1; - - orbit=Vector2(0,0); - up_vector=Vector3(0,1,0); - - distance=3; - min_distance=2; - max_distance=5; - - autoturn=true; - autoturn_tolerance=10; - autoturn_speed=80; - - min_orbit_x=-50; - max_orbit_x=70; - inclination=0; - target_width=0.3; - - clip=true; - use_lookat_target = false; - extraclip=0.3; - fullclip=false; - - smooth=true; - smooth_rot_ratio=10; - smooth_pos_ratio=10; - - - for(int i=0;i<3;i++) { -// clip_ray[i].query=PhysicsServer::get_singleton()->query_create(this, "_ray_collision", i, true); - clip_ray[i].clipped=false; - } - - queries_active=false; - - -} - -FollowCamera::~FollowCamera() { - - for(int i=0;i<3;i++) { - PhysicsServer::get_singleton()->free(clip_ray[i].query); - } - - -} diff --git a/scene/3d/follow_camera.h b/scene/3d/follow_camera.h deleted file mode 100644 index 10912eb606..0000000000 --- a/scene/3d/follow_camera.h +++ /dev/null @@ -1,180 +0,0 @@ -/*************************************************************************/ -/* follow_camera.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef FOLLOW_CAMERA_H -#define FOLLOW_CAMERA_H - -#include "scene/3d/camera.h" - -class FollowCamera : public Camera { - - OBJ_TYPE( FollowCamera, Camera ); - -private: - - - //used for follow - Vector3 follow_pos; - //used for fixed - Vector2 initial_orbit; - Vector2 orbit; - float distance; - - float height; - float target_width; - - float min_distance; - float max_distance; - - float max_orbit_x; - float min_orbit_x; - - float inclination; - float extraclip; - bool fullclip; - - bool clip; - bool autoturn; - float autoturn_tolerance; - float autoturn_speed; - - bool smooth; - float smooth_rot_ratio; - float smooth_pos_ratio; - - - - struct ClipRay { - RID query; - bool clipped; - Vector3 cast_pos; - Vector3 clip_pos; - }; - - ClipRay clip_ray[3]; - Vector3 target_pos; - float clip_len; - - Vector3 up_vector; - - - virtual RES _get_gizmo_geometry() const; - - Transform ted; - Vector3 proposed_pos; - Transform accepted; - Transform final; - RID target_body; - - bool use_lookat_target; - Vector3 lookat_target; - - void _compute_camera(); - - bool queries_active; - void _clear_queries(); - - void _set_initial_orbit(const Vector2& p_orbit); - -protected: - - virtual void _request_camera_update() {} //ignore - - void _notification(int p_what); - - static void _bind_methods(); - - void _ray_collision(Vector3 p_point, Vector3 p_normal, int p_subindex, ObjectID p_against,int p_idx); - -public: - - - void set_orbit(const Vector2& p_orbit); - void set_orbit_x(float p_x); - void set_orbit_y(float p_y); - Vector2 get_orbit() const; - - void set_height(float p_height); - float get_height() const; - - void set_inclination(float p_degrees); - float get_inclination() const; - - void set_max_orbit_x(float p_max); - float get_max_orbit_x() const; - - void set_min_orbit_x(float p_min); - float get_min_orbit_x() const; - - void rotate_orbit(const Vector2& p_relative); - - void set_distance(float p_distance); - float get_distance() const; - - float get_min_distance() const; - float get_max_distance() const; - void set_min_distance(float p_min); - void set_max_distance(float p_max); - - /** FINISH THIS AND CLEAN IT UP */ - - void set_clip(bool p_enabled); - bool has_clip() const; - - void set_autoturn(bool p_enabled); - bool has_autoturn() const; - - void set_autoturn_tolerance(float p_degrees); - float get_autoturn_tolerance() const; - - void set_autoturn_speed(float p_speed); - float get_autoturn_speed() const; - - void set_smoothing(bool p_enable); - bool has_smoothing() const; - - void set_translation_smoothing(float p_amount); - float get_translation_smoothing() const; - - void set_rotation_smoothing(float p_amount); - float get_rotation_smoothing() const; - - void set_use_lookat_target(bool p_use, const Vector3 &p_lookat = Vector3()); - - void set_up_vector(const Vector3& p_up); - Vector3 get_up_vector() const; - - virtual Transform get_camera_transform() const; - - FollowCamera(); - ~FollowCamera(); -}; - - - -#endif // FOLLOW_CAMERA_H diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp index 1459f2c362..651d20ae71 100644 --- a/scene/3d/immediate_geometry.cpp +++ b/scene/3d/immediate_geometry.cpp @@ -72,6 +72,53 @@ DVector<Face3> ImmediateGeometry::get_faces(uint32_t p_usage_flags) const { return DVector<Face3>(); } + + +void ImmediateGeometry::add_sphere(int p_lats,int p_lons,float p_radius) { + + for(int i = 1; i <= p_lats; i++) { + double lat0 = Math_PI * (-0.5 + (double) (i - 1) / p_lats); + double z0 = Math::sin(lat0); + double zr0 = Math::cos(lat0); + + double lat1 = Math_PI * (-0.5 + (double) i / p_lats); + double z1 = Math::sin(lat1); + double zr1 = Math::cos(lat1); + + for(int j = p_lons; j >= 1; j--) { + + double lng0 = 2 * Math_PI * (double) (j - 1) / p_lons; + double x0 = Math::cos(lng0); + double y0 = Math::sin(lng0); + + double lng1 = 2 * Math_PI * (double) (j) / p_lons; + double x1 = Math::cos(lng1); + double y1 = Math::sin(lng1); + + + Vector3 v[4]={ + Vector3(x1 * zr0, z0, y1 *zr0), + Vector3(x1 * zr1, z1, y1 *zr1), + Vector3(x0 * zr1, z1, y0 *zr1), + Vector3(x0 * zr0, z0, y0 *zr0) + }; + +#define ADD_POINT(m_idx)\ + set_normal(v[m_idx]);\ + add_vertex(v[m_idx]*p_radius); + + ADD_POINT(0); + ADD_POINT(1); + ADD_POINT(2); + + ADD_POINT(2); + ADD_POINT(3); + ADD_POINT(0); + } + } + +} + void ImmediateGeometry::_bind_methods() { ObjectTypeDB::bind_method(_MD("begin","primitive","texture:Texture"),&ImmediateGeometry::begin); @@ -80,12 +127,15 @@ void ImmediateGeometry::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_color","color"),&ImmediateGeometry::set_color); ObjectTypeDB::bind_method(_MD("set_uv","uv"),&ImmediateGeometry::set_uv); ObjectTypeDB::bind_method(_MD("set_uv2","uv"),&ImmediateGeometry::set_uv2); - ObjectTypeDB::bind_method(_MD("add_vertex","color"),&ImmediateGeometry::add_vertex); + ObjectTypeDB::bind_method(_MD("add_vertex","pos"),&ImmediateGeometry::add_vertex); + ObjectTypeDB::bind_method(_MD("add_sphere","lats","lons","radius"),&ImmediateGeometry::add_sphere); ObjectTypeDB::bind_method(_MD("end"),&ImmediateGeometry::end); ObjectTypeDB::bind_method(_MD("clear"),&ImmediateGeometry::clear); } + + ImmediateGeometry::ImmediateGeometry() { im = VisualServer::get_singleton()->immediate_create(); diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h index 2db81134c6..beb8ea8214 100644 --- a/scene/3d/immediate_geometry.h +++ b/scene/3d/immediate_geometry.h @@ -31,6 +31,11 @@ public: void end(); void clear(); + + void add_sphere(int p_lats,int p_lons,float p_radius); + + + virtual AABB get_aabb() const; virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp index 4d8c9cf7a5..2f35164f49 100644 --- a/scene/3d/interpolated_camera.cpp +++ b/scene/3d/interpolated_camera.cpp @@ -32,9 +32,9 @@ void InterpolatedCamera::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { - if (get_scene()->is_editor_hint() && enabled) + if (get_tree()->is_editor_hint() && enabled) set_fixed_process(false); } break; @@ -50,7 +50,7 @@ void InterpolatedCamera::_notification(int p_what) { float delta = speed*get_process_delta_time(); Transform target_xform = node->get_global_transform(); - Transform local_transform = get_transform(); + Transform local_transform = get_global_transform(); local_transform = local_transform.interpolate_with(target_xform,delta); set_global_transform(local_transform); @@ -109,7 +109,7 @@ void InterpolatedCamera::set_interpolation_enabled(bool p_enable) { return; enabled=p_enable; if (p_enable) { - if (is_inside_scene() && get_scene()->is_editor_hint()) + if (is_inside_tree() && get_tree()->is_editor_hint()) return; set_process(true); } else @@ -136,7 +136,7 @@ void InterpolatedCamera::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_target_path","target_path"),&InterpolatedCamera::set_target_path); ObjectTypeDB::bind_method(_MD("get_target_path"),&InterpolatedCamera::get_target_path); - ObjectTypeDB::bind_method(_MD("set_target","target"),&InterpolatedCamera::_set_target); + ObjectTypeDB::bind_method(_MD("set_target","target:Camera"),&InterpolatedCamera::_set_target); ObjectTypeDB::bind_method(_MD("set_speed","speed"),&InterpolatedCamera::set_speed); ObjectTypeDB::bind_method(_MD("get_speed"),&InterpolatedCamera::get_speed); diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp index 1efc74e672..15e77e5378 100644 --- a/scene/3d/light.cpp +++ b/scene/3d/light.cpp @@ -415,11 +415,11 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo float energy=1.0; - if (p_constant>0) + /*if (p_constant>0) energy=1.0/p_constant; //energy is this else energy=8.0; // some high number.. - +*/ if (radius==10000) radius=100; //bug? @@ -429,10 +429,42 @@ void Light::approximate_opengl_attenuation(float p_constant, float p_linear, flo } + +void Light::_update_visibility() { + + if (!is_inside_tree()) + return; + + +bool editor_ok=true; + +#ifdef TOOLS_ENABLED + if (editor_only) { + if (!get_tree()->is_editor_hint()) { + editor_ok=false; + } else { + editor_ok = (get_tree()->get_edited_scene_root() && (this==get_tree()->get_edited_scene_root() || get_owner()==get_tree()->get_edited_scene_root())); + } + } +#endif + + VS::get_singleton()->instance_light_set_enabled(get_instance(),is_visible() && enabled && editor_ok); + _change_notify("geometry/visible"); + +} + + +void Light::_notification(int p_what) { + + if (p_what==NOTIFICATION_ENTER_TREE || p_what==NOTIFICATION_VISIBILITY_CHANGED) { + _update_visibility(); + } +} + void Light::set_enabled(bool p_enabled) { enabled=p_enabled; - VS::get_singleton()->instance_light_set_enabled(get_instance(),enabled); + _update_visibility(); } bool Light::is_enabled() const{ @@ -440,6 +472,17 @@ bool Light::is_enabled() const{ return enabled; } +void Light::set_editor_only(bool p_editor_only) { + + editor_only=p_editor_only; + _update_visibility(); +} + +bool Light::is_editor_only() const{ + + return editor_only; +} + void Light::_bind_methods() { @@ -457,9 +500,12 @@ void Light::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_bake_mode"), &Light::get_bake_mode ); ObjectTypeDB::bind_method(_MD("set_enabled","enabled"), &Light::set_enabled ); ObjectTypeDB::bind_method(_MD("is_enabled"), &Light::is_enabled ); + ObjectTypeDB::bind_method(_MD("set_editor_only","editor_only"), &Light::set_editor_only ); + ObjectTypeDB::bind_method(_MD("is_editor_only"), &Light::is_editor_only ); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/enabled"), _SCS("set_enabled"), _SCS("is_enabled")); + ADD_PROPERTY( PropertyInfo( Variant::BOOL, "params/editor_only"), _SCS("set_editor_only"), _SCS("is_editor_only")); ADD_PROPERTY( PropertyInfo( Variant::INT, "params/bake_mode",PROPERTY_HINT_ENUM,"Disabled,Indirect,Indirect+Shadows,Full"), _SCS("set_bake_mode"), _SCS("get_bake_mode")); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/energy", PROPERTY_HINT_EXP_RANGE, "0,64,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ENERGY ); /* @@ -531,6 +577,7 @@ Light::Light(VisualServer::LightType p_type) { set_project_shadows( false ); set_base(light); enabled=true; + editor_only=false; bake_mode=BAKE_MODE_DISABLED; } @@ -622,7 +669,7 @@ void SpotLight::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION ); ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_angle", PROPERTY_HINT_RANGE, "0.01,89.9,0.01"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ANGLE ); - ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_ATTENUATION ); + ADD_PROPERTYI( PropertyInfo( Variant::REAL, "params/spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPOT_ATTENUATION ); } diff --git a/scene/3d/light.h b/scene/3d/light.h index 8e7395fd84..6fb57a269b 100644 --- a/scene/3d/light.h +++ b/scene/3d/light.h @@ -92,8 +92,10 @@ private: VisualServer::LightType type; bool shadows; bool enabled; + bool editor_only; Operator op; - + + void _update_visibility(); // bind helpers protected: @@ -104,6 +106,7 @@ protected: virtual RES _get_gizmo_geometry() const; static void _bind_methods(); + void _notification(int p_what); Light(VisualServer::LightType p_type); @@ -132,6 +135,9 @@ public: void set_enabled(bool p_enabled); bool is_enabled() const; + void set_editor_only(bool p_editor_only); + bool is_editor_only() const; + virtual AABB get_aabb() const; virtual DVector<Face3> get_faces(uint32_t p_usage_flags) const; diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp index 40981d468e..d7266e5df7 100644 --- a/scene/3d/mesh_instance.cpp +++ b/scene/3d/mesh_instance.cpp @@ -30,7 +30,7 @@ #include "skeleton.h" #include "physics_body.h" - +#include "body_shape.h" bool MeshInstance::_set(const StringName& p_name, const Variant& p_value) { @@ -126,7 +126,7 @@ void MeshInstance::_resolve_skeleton_path(){ void MeshInstance::set_skeleton_path(const NodePath &p_skeleton) { skeleton_path = p_skeleton; - if (!is_inside_scene()) + if (!is_inside_tree()) return; _resolve_skeleton_path(); } @@ -181,6 +181,11 @@ void MeshInstance::create_trimesh_collision() { add_child(static_body); if (get_owner()) static_body->set_owner( get_owner() ); + CollisionShape *cshape = memnew( CollisionShape ); + cshape->set_shape(static_body->get_shape(0)); + static_body->add_child(cshape); + if (get_owner()) + cshape->set_owner( get_owner() ); } @@ -210,12 +215,18 @@ void MeshInstance::create_convex_collision() { add_child(static_body); if (get_owner()) static_body->set_owner( get_owner() ); + CollisionShape *cshape = memnew( CollisionShape ); + cshape->set_shape(static_body->get_shape(0)); + static_body->add_child(cshape); + if (get_owner()) + cshape->set_owner( get_owner() ); + } void MeshInstance::_notification(int p_what) { - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { _resolve_skeleton_path(); } } @@ -229,9 +240,9 @@ void MeshInstance::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_skeleton_path:NodePath"),&MeshInstance::get_skeleton_path); ObjectTypeDB::bind_method(_MD("get_aabb"),&MeshInstance::get_aabb); ObjectTypeDB::bind_method(_MD("create_trimesh_collision"),&MeshInstance::create_trimesh_collision); - ObjectTypeDB::set_method_flags("MeshInstance","create_trimesh_collision",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::set_method_flags("MeshInstance","create_trimesh_collision",METHOD_FLAGS_DEFAULT); ObjectTypeDB::bind_method(_MD("create_convex_collision"),&MeshInstance::create_convex_collision); - ObjectTypeDB::set_method_flags("MeshInstance","create_convex_collision",METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::set_method_flags("MeshInstance","create_convex_collision",METHOD_FLAGS_DEFAULT); ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "mesh/mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh" ), _SCS("set_mesh"), _SCS("get_mesh")); ADD_PROPERTY( PropertyInfo (Variant::NODE_PATH, "mesh/skeleton"), _SCS("set_skeleton_path"), _SCS("get_skeleton_path")); } diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp index d2abdad079..ce002fb44b 100644 --- a/scene/3d/navigation.cpp +++ b/scene/3d/navigation.cpp @@ -21,6 +21,7 @@ void Navigation::_navmesh_link(int p_id) { List<Polygon>::Element *P=nm.polygons.push_back(Polygon()); Polygon &p=P->get(); + p.owner=&nm; Vector<int> poly = nm.navmesh->get_polygon(i); int plen=poly.size(); @@ -145,13 +146,14 @@ void Navigation::_navmesh_unlink(int p_id) { } -int Navigation::navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform) { +int Navigation::navmesh_create(const Ref<NavigationMesh>& p_mesh, const Transform& p_xform, Object *p_owner) { int id = last_id++; NavMesh nm; nm.linked=false; nm.navmesh=p_mesh; nm.xform=p_xform; + nm.owner=p_owner; navmesh_map[id]=nm; _navmesh_link(id); @@ -180,6 +182,41 @@ void Navigation::navmesh_remove(int p_id){ } +void Navigation::_clip_path(Vector<Vector3>& path, Polygon *from_poly, const Vector3& p_to_point, Polygon* p_to_poly) { + + Vector3 from = path[path.size()-1]; + + if (from.distance_to(p_to_point)<CMP_EPSILON) + return; + Plane cut_plane; + cut_plane.normal = (from-p_to_point).cross(up); + if (cut_plane.normal==Vector3()) + return; + cut_plane.normal.normalize(); + cut_plane.d = cut_plane.normal.dot(from); + + + while(from_poly!=p_to_poly) { + + int pe = from_poly->prev_edge; + Vector3 a = _get_vertex(from_poly->edges[pe].point); + Vector3 b = _get_vertex(from_poly->edges[(pe+1)%from_poly->edges.size()].point); + + from_poly=from_poly->edges[pe].C; + ERR_FAIL_COND(!from_poly); + + if (a.distance_to(b)>CMP_EPSILON) { + + Vector3 inters; + if (cut_plane.intersects_segment(a,b,&inters)) { + if (inters.distance_to(p_to_point)>CMP_EPSILON && inters.distance_to(path[path.size()-1])>CMP_EPSILON) { + path.push_back(inters); + } + } + } + } +} + Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector3& p_end, bool p_optimize) { @@ -377,9 +414,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector portal_left=left; } else { - apex_point=portal_right; + _clip_path(path,apex_poly,portal_right,right_poly); + + apex_point=portal_right; p=right_poly; left_poly=p; + apex_poly=p; portal_left=apex_point; portal_right=apex_point; path.push_back(apex_point); @@ -394,9 +434,12 @@ Vector<Vector3> Navigation::get_simple_path(const Vector3& p_start, const Vector portal_right=right; } else { + _clip_path(path,apex_poly,portal_left,left_poly); + apex_point=portal_left; p=left_poly; right_poly=p; + apex_poly=p; portal_right=apex_point; portal_left=apex_point; path.push_back(apex_point); @@ -453,6 +496,7 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3& p_from,const Vec bool use_collision=false; Vector3 closest_point; float closest_point_d=1e20; + NavMesh *closest_navmesh=NULL; for (Map<int,NavMesh>::Element*E=navmesh_map.front();E;E=E->next()) { @@ -471,10 +515,12 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3& p_from,const Vec closest_point=inters; use_collision=true; closest_point_d=p_from.distance_to(inters); + closest_navmesh=p.owner; } else if (closest_point_d > inters.distance_to(p_from)){ closest_point=inters; closest_point_d=p_from.distance_to(inters); + closest_navmesh=p.owner; } } } @@ -492,6 +538,7 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3& p_from,const Vec closest_point_d=d; closest_point=b; + closest_navmesh=p.owner; } } @@ -499,6 +546,10 @@ Vector3 Navigation::get_closest_point_to_segment(const Vector3& p_from,const Vec } } + if (closest_navmesh && closest_navmesh->owner) { + //print_line("navmesh is: "+closest_navmesh->owner->cast_to<Node>()->get_name()); + } + return closest_point; } @@ -577,7 +628,7 @@ Vector3 Navigation::get_up_vector() const{ void Navigation::_bind_methods() { - ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform"),&Navigation::navmesh_create); + ObjectTypeDB::bind_method(_MD("navmesh_create","mesh:NavigationMesh","xform","owner"),&Navigation::navmesh_create,DEFVAL(Variant())); ObjectTypeDB::bind_method(_MD("navmesh_set_transform","id","xform"),&Navigation::navmesh_set_transform); ObjectTypeDB::bind_method(_MD("navmesh_remove","id"),&Navigation::navmesh_remove); diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h index e8a97a6591..69d48531a7 100644 --- a/scene/3d/navigation.h +++ b/scene/3d/navigation.h @@ -41,6 +41,8 @@ class Navigation : public Spatial { }; + struct NavMesh; + struct Polygon { @@ -57,6 +59,8 @@ class Navigation : public Spatial { float distance; int prev_edge; + + NavMesh *owner; }; @@ -74,6 +78,7 @@ class Navigation : public Spatial { struct NavMesh { + Object *owner; Transform xform; bool linked; Ref<NavigationMesh> navmesh; @@ -113,6 +118,7 @@ class Navigation : public Spatial { int last_id; Vector3 up; + void _clip_path(Vector<Vector3>& path,Polygon *from_poly, const Vector3& p_to_point, Polygon* p_to_poly); protected: @@ -124,7 +130,7 @@ public: Vector3 get_up_vector() const; //API should be as dynamic as possible - int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform); + int navmesh_create(const Ref<NavigationMesh>& p_mesh,const Transform& p_xform,Object* p_owner=NULL); void navmesh_set_transform(int p_id, const Transform& p_xform); void navmesh_remove(int p_id); diff --git a/scene/3d/navigation_mesh.cpp b/scene/3d/navigation_mesh.cpp index cf2e22a573..8c52d4c35c 100644 --- a/scene/3d/navigation_mesh.cpp +++ b/scene/3d/navigation_mesh.cpp @@ -114,7 +114,7 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) { return; enabled=p_enabled; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (!enabled) { @@ -129,7 +129,7 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) { if (navmesh.is_valid()) { - nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation)); + nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this); } } @@ -152,7 +152,7 @@ void NavigationMeshInstance::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { Spatial *c=this; while(c) { @@ -162,7 +162,7 @@ void NavigationMeshInstance::_notification(int p_what) { if (enabled && navmesh.is_valid()) { - nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation)); + nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this); } break; } @@ -178,7 +178,7 @@ void NavigationMeshInstance::_notification(int p_what) { } } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (navigation) { @@ -205,7 +205,7 @@ void NavigationMeshInstance::set_navigation_mesh(const Ref<NavigationMesh>& p_na navmesh=p_navmesh; if (navigation && navmesh.is_valid() && enabled) { - nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation)); + nav_id = navigation->navmesh_create(navmesh,get_relative_transform(navigation),this); } update_gizmo(); diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp index bc5cb1c4a2..8be918fc22 100644 --- a/scene/3d/path.cpp +++ b/scene/3d/path.cpp @@ -26,363 +26,363 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "path.h"
-#include "scene/scene_string_names.h"
-
-void Path::_notification(int p_what) {
-#if 0
- if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) {
- //draw the curve!!
-
- for(int i=0;i<curve->get_point_count();i++) {
-
- Vector2 prev_p=curve->get_point_pos(i);
-
- for(int j=1;j<=8;j++) {
-
- real_t frac = j/8.0;
- Vector2 p = curve->interpolate(i,frac);
- draw_line(prev_p,p,Color(0.5,0.6,1.0,0.7),2);
- prev_p=p;
- }
- }
- }
-#endif
-}
-
-void Path::_curve_changed() {
-
-
- if (is_inside_scene() && get_scene()->is_editor_hint())
- update_gizmo();
-}
-
-
-void Path::set_curve(const Ref<Curve3D>& p_curve) {
-
- if (curve.is_valid()) {
- curve->disconnect("changed",this,"_curve_changed");
- }
-
- curve=p_curve;
-
- if (curve.is_valid()) {
- curve->connect("changed",this,"_curve_changed");
- }
- _curve_changed();
-
-}
-
-Ref<Curve3D> Path::get_curve() const{
-
- return curve;
-}
-
-void Path::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve3D"),&Path::set_curve);
- ObjectTypeDB::bind_method(_MD("get_curve:Curve3D","curve"),&Path::get_curve);
- ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path::_curve_changed);
-
- ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), _SCS("set_curve"),_SCS("get_curve"));
-}
-
-Path::Path() {
-
- set_curve(Ref<Curve3D>( memnew( Curve3D ))); //create one by default
-}
-
-
-//////////////
-
-
-void PathFollow::_update_transform() {
-
-
- if (!path)
- return;
-
- Ref<Curve3D> c =path->get_curve();
- if (!c.is_valid())
- return;
-
-
- float o = offset;
- if (loop)
- o=Math::fposmod(o,c->get_baked_length());
-
- Vector3 pos = c->interpolate_baked(o,cubic);
- Transform t=get_transform();
-
-
- if (rotation_mode!=ROTATION_NONE) {
-
- Vector3 n = (c->interpolate_baked(o+lookahead,cubic)-pos).normalized();
-
- if (rotation_mode==ROTATION_Y) {
-
- n.y=0;
- n.normalize();
- }
-
- if (n.length()<CMP_EPSILON) {//nothing, use previous
- n=-t.get_basis().get_axis(2).normalized();
- }
-
-
- Vector3 up = Vector3(0,1,0);
-
- if (rotation_mode==ROTATION_XYZ) {
-
- float tilt = c->interpolate_baked_tilt(o);
- if (tilt!=0) {
-
- Matrix3 rot(-n,tilt); //remember.. lookat will be znegative.. znegative!! we abide by opengl clan.
- up=rot.xform(up);
- }
- }
-
- t.set_look_at(pos,pos+n,up);
-
- } else {
-
- t.origin=pos;
- }
-
- t.origin+=t.basis.get_axis(0)*h_offset + t.basis.get_axis(1)*v_offset;
- set_transform(t);
-
-}
-
-void PathFollow::_notification(int p_what) {
-
-
- switch(p_what) {
-
- case NOTIFICATION_ENTER_SCENE: {
-
- Node *parent=get_parent();
- if (parent) {
-
- path=parent->cast_to<Path>();
- if (path) {
- _update_transform();
- }
- }
-
- } break;
- case NOTIFICATION_EXIT_SCENE: {
-
-
- path=NULL;
- } break;
- }
-
-}
-
-void PathFollow::set_cubic_interpolation(bool p_enable) {
-
- cubic=p_enable;
-}
-
-bool PathFollow::get_cubic_interpolation() const {
-
- return cubic;
-}
-
-
-bool PathFollow::_set(const StringName& p_name, const Variant& p_value) {
-
- if (p_name==SceneStringNames::get_singleton()->offset) {
- set_offset(p_value);
- } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
- set_unit_offset(p_value);
- } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
- set_rotation_mode(RotationMode(p_value.operator int()));
- } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
- set_v_offset(p_value);
- } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
- set_h_offset(p_value);
- } else if (String(p_name)=="cubic_interp") {
- set_cubic_interpolation(p_value);
- } else if (String(p_name)=="loop") {
- set_loop(p_value);
- } else if (String(p_name)=="lookahead") {
- set_lookahead(p_value);
- } else
- return false;
-
- return true;
-}
-
-bool PathFollow::_get(const StringName& p_name,Variant &r_ret) const{
-
- if (p_name==SceneStringNames::get_singleton()->offset) {
- r_ret=get_offset();
- } else if (p_name==SceneStringNames::get_singleton()->unit_offset) {
- r_ret=get_unit_offset();
- } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) {
- r_ret=get_rotation_mode();
- } else if (p_name==SceneStringNames::get_singleton()->v_offset) {
- r_ret=get_v_offset();
- } else if (p_name==SceneStringNames::get_singleton()->h_offset) {
- r_ret=get_h_offset();
- } else if (String(p_name)=="cubic_interp") {
- r_ret=cubic;
- } else if (String(p_name)=="loop") {
- r_ret=loop;
- } else if (String(p_name)=="lookahead") {
- r_ret=lookahead;
- } else
- return false;
-
- return true;
-
-}
-void PathFollow::_get_property_list( List<PropertyInfo> *p_list) const{
-
- float max=10000;
- if (path && path->get_curve().is_valid())
- max=path->get_curve()->get_baked_length();
- p_list->push_back( PropertyInfo( Variant::REAL, "offset", PROPERTY_HINT_RANGE,"0,"+rtos(max)+",0.01"));
- p_list->push_back( PropertyInfo( Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE,"0,1,0.0001",PROPERTY_USAGE_EDITOR));
- p_list->push_back( PropertyInfo( Variant::REAL, "h_offset") );
- p_list->push_back( PropertyInfo( Variant::REAL, "v_offset") );
- p_list->push_back( PropertyInfo( Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM,"None,Y,XY,XYZ"));
- p_list->push_back( PropertyInfo( Variant::BOOL, "cubic_interp"));
- p_list->push_back( PropertyInfo( Variant::BOOL, "loop"));
- p_list->push_back( PropertyInfo( Variant::REAL, "lookahead",PROPERTY_HINT_RANGE,"0.001,1024.0,0.001"));
-}
-
-
-void PathFollow::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("set_offset","offset"),&PathFollow::set_offset);
- ObjectTypeDB::bind_method(_MD("get_offset"),&PathFollow::get_offset);
-
- ObjectTypeDB::bind_method(_MD("set_h_offset","h_offset"),&PathFollow::set_h_offset);
- ObjectTypeDB::bind_method(_MD("get_h_offset"),&PathFollow::get_h_offset);
-
- ObjectTypeDB::bind_method(_MD("set_v_offset","v_offset"),&PathFollow::set_v_offset);
- ObjectTypeDB::bind_method(_MD("get_v_offset"),&PathFollow::get_v_offset);
-
- ObjectTypeDB::bind_method(_MD("set_unit_offset","unit_offset"),&PathFollow::set_unit_offset);
- ObjectTypeDB::bind_method(_MD("get_unit_offset"),&PathFollow::get_unit_offset);
-
- ObjectTypeDB::bind_method(_MD("set_rotation_mode","rotation_mode"),&PathFollow::set_rotation_mode);
- ObjectTypeDB::bind_method(_MD("get_rotation_mode"),&PathFollow::get_rotation_mode);
-
- ObjectTypeDB::bind_method(_MD("set_cubic_interpolation","enable"),&PathFollow::set_cubic_interpolation);
- ObjectTypeDB::bind_method(_MD("get_cubic_interpolation"),&PathFollow::get_cubic_interpolation);
-
- ObjectTypeDB::bind_method(_MD("set_loop","loop"),&PathFollow::set_loop);
- ObjectTypeDB::bind_method(_MD("has_loop"),&PathFollow::has_loop);
-
- BIND_CONSTANT( ROTATION_NONE );
- BIND_CONSTANT( ROTATION_Y );
- BIND_CONSTANT( ROTATION_XY );
- BIND_CONSTANT( ROTATION_XYZ );
-
-}
-
-void PathFollow::set_offset(float p_offset) {
-
- offset=p_offset;
- if (path)
- _update_transform();
- _change_notify("offset");
- _change_notify("unit_offset");
-
-}
-
-void PathFollow::set_h_offset(float p_h_offset) {
-
- h_offset=p_h_offset;
- if (path)
- _update_transform();
-
-}
-
-float PathFollow::get_h_offset() const {
-
- return h_offset;
-}
-
-void PathFollow::set_v_offset(float p_v_offset) {
-
- v_offset=p_v_offset;
- if (path)
- _update_transform();
-
-}
-
-float PathFollow::get_v_offset() const {
-
- return v_offset;
-}
-
-
-float PathFollow::get_offset() const{
-
- return offset;
-}
-
-void PathFollow::set_unit_offset(float p_unit_offset) {
-
- if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
- set_offset(p_unit_offset*path->get_curve()->get_baked_length());
-
-}
-
-float PathFollow::get_unit_offset() const{
-
- if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length())
- return get_offset()/path->get_curve()->get_baked_length();
- else
- return 0;
-}
-
-void PathFollow::set_lookahead(float p_lookahead) {
-
- lookahead=p_lookahead;
-
-}
-
-float PathFollow::get_lookahead() const{
-
- return lookahead;
-}
-
-void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) {
-
- rotation_mode=p_rotation_mode;
- _update_transform();
-}
-
-PathFollow::RotationMode PathFollow::get_rotation_mode() const {
-
- return rotation_mode;
-}
-
-void PathFollow::set_loop(bool p_loop) {
-
- loop=p_loop;
-}
-
-bool PathFollow::has_loop() const{
-
- return loop;
-}
-
-
-PathFollow::PathFollow() {
-
- offset=0;
- h_offset=0;
- v_offset=0;
- path=NULL;
- rotation_mode=ROTATION_XYZ;
- cubic=true;
- loop=true;
- lookahead=0.1;
-}
+#include "path.h" +#include "scene/scene_string_names.h" + +void Path::_notification(int p_what) { +#if 0 + if (p_what==NOTIFICATION_DRAW && curve.is_valid() && is_inside_scene() && get_scene()->is_editor_hint()) { + //draw the curve!! + + for(int i=0;i<curve->get_point_count();i++) { + + Vector2 prev_p=curve->get_point_pos(i); + + for(int j=1;j<=8;j++) { + + real_t frac = j/8.0; + Vector2 p = curve->interpolate(i,frac); + draw_line(prev_p,p,Color(0.5,0.6,1.0,0.7),2); + prev_p=p; + } + } + } +#endif +} + +void Path::_curve_changed() { + + + if (is_inside_tree() && get_tree()->is_editor_hint()) + update_gizmo(); +} + + +void Path::set_curve(const Ref<Curve3D>& p_curve) { + + if (curve.is_valid()) { + curve->disconnect("changed",this,"_curve_changed"); + } + + curve=p_curve; + + if (curve.is_valid()) { + curve->connect("changed",this,"_curve_changed"); + } + _curve_changed(); + +} + +Ref<Curve3D> Path::get_curve() const{ + + return curve; +} + +void Path::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_curve","curve:Curve3D"),&Path::set_curve); + ObjectTypeDB::bind_method(_MD("get_curve:Curve3D","curve"),&Path::get_curve); + ObjectTypeDB::bind_method(_MD("_curve_changed"),&Path::_curve_changed); + + ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), _SCS("set_curve"),_SCS("get_curve")); +} + +Path::Path() { + + set_curve(Ref<Curve3D>( memnew( Curve3D ))); //create one by default +} + + +////////////// + + +void PathFollow::_update_transform() { + + + if (!path) + return; + + Ref<Curve3D> c =path->get_curve(); + if (!c.is_valid()) + return; + + + float o = offset; + if (loop) + o=Math::fposmod(o,c->get_baked_length()); + + Vector3 pos = c->interpolate_baked(o,cubic); + Transform t=get_transform(); + + + if (rotation_mode!=ROTATION_NONE) { + + Vector3 n = (c->interpolate_baked(o+lookahead,cubic)-pos).normalized(); + + if (rotation_mode==ROTATION_Y) { + + n.y=0; + n.normalize(); + } + + if (n.length()<CMP_EPSILON) {//nothing, use previous + n=-t.get_basis().get_axis(2).normalized(); + } + + + Vector3 up = Vector3(0,1,0); + + if (rotation_mode==ROTATION_XYZ) { + + float tilt = c->interpolate_baked_tilt(o); + if (tilt!=0) { + + Matrix3 rot(-n,tilt); //remember.. lookat will be znegative.. znegative!! we abide by opengl clan. + up=rot.xform(up); + } + } + + t.set_look_at(pos,pos+n,up); + + } else { + + t.origin=pos; + } + + t.origin+=t.basis.get_axis(0)*h_offset + t.basis.get_axis(1)*v_offset; + set_transform(t); + +} + +void PathFollow::_notification(int p_what) { + + + switch(p_what) { + + case NOTIFICATION_ENTER_TREE: { + + Node *parent=get_parent(); + if (parent) { + + path=parent->cast_to<Path>(); + if (path) { + _update_transform(); + } + } + + } break; + case NOTIFICATION_EXIT_TREE: { + + + path=NULL; + } break; + } + +} + +void PathFollow::set_cubic_interpolation(bool p_enable) { + + cubic=p_enable; +} + +bool PathFollow::get_cubic_interpolation() const { + + return cubic; +} + + +bool PathFollow::_set(const StringName& p_name, const Variant& p_value) { + + if (p_name==SceneStringNames::get_singleton()->offset) { + set_offset(p_value); + } else if (p_name==SceneStringNames::get_singleton()->unit_offset) { + set_unit_offset(p_value); + } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) { + set_rotation_mode(RotationMode(p_value.operator int())); + } else if (p_name==SceneStringNames::get_singleton()->v_offset) { + set_v_offset(p_value); + } else if (p_name==SceneStringNames::get_singleton()->h_offset) { + set_h_offset(p_value); + } else if (String(p_name)=="cubic_interp") { + set_cubic_interpolation(p_value); + } else if (String(p_name)=="loop") { + set_loop(p_value); + } else if (String(p_name)=="lookahead") { + set_lookahead(p_value); + } else + return false; + + return true; +} + +bool PathFollow::_get(const StringName& p_name,Variant &r_ret) const{ + + if (p_name==SceneStringNames::get_singleton()->offset) { + r_ret=get_offset(); + } else if (p_name==SceneStringNames::get_singleton()->unit_offset) { + r_ret=get_unit_offset(); + } else if (p_name==SceneStringNames::get_singleton()->rotation_mode) { + r_ret=get_rotation_mode(); + } else if (p_name==SceneStringNames::get_singleton()->v_offset) { + r_ret=get_v_offset(); + } else if (p_name==SceneStringNames::get_singleton()->h_offset) { + r_ret=get_h_offset(); + } else if (String(p_name)=="cubic_interp") { + r_ret=cubic; + } else if (String(p_name)=="loop") { + r_ret=loop; + } else if (String(p_name)=="lookahead") { + r_ret=lookahead; + } else + return false; + + return true; + +} +void PathFollow::_get_property_list( List<PropertyInfo> *p_list) const{ + + float max=10000; + if (path && path->get_curve().is_valid()) + max=path->get_curve()->get_baked_length(); + p_list->push_back( PropertyInfo( Variant::REAL, "offset", PROPERTY_HINT_RANGE,"0,"+rtos(max)+",0.01")); + p_list->push_back( PropertyInfo( Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE,"0,1,0.0001",PROPERTY_USAGE_EDITOR)); + p_list->push_back( PropertyInfo( Variant::REAL, "h_offset") ); + p_list->push_back( PropertyInfo( Variant::REAL, "v_offset") ); + p_list->push_back( PropertyInfo( Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM,"None,Y,XY,XYZ")); + p_list->push_back( PropertyInfo( Variant::BOOL, "cubic_interp")); + p_list->push_back( PropertyInfo( Variant::BOOL, "loop")); + p_list->push_back( PropertyInfo( Variant::REAL, "lookahead",PROPERTY_HINT_RANGE,"0.001,1024.0,0.001")); +} + + +void PathFollow::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_offset","offset"),&PathFollow::set_offset); + ObjectTypeDB::bind_method(_MD("get_offset"),&PathFollow::get_offset); + + ObjectTypeDB::bind_method(_MD("set_h_offset","h_offset"),&PathFollow::set_h_offset); + ObjectTypeDB::bind_method(_MD("get_h_offset"),&PathFollow::get_h_offset); + + ObjectTypeDB::bind_method(_MD("set_v_offset","v_offset"),&PathFollow::set_v_offset); + ObjectTypeDB::bind_method(_MD("get_v_offset"),&PathFollow::get_v_offset); + + ObjectTypeDB::bind_method(_MD("set_unit_offset","unit_offset"),&PathFollow::set_unit_offset); + ObjectTypeDB::bind_method(_MD("get_unit_offset"),&PathFollow::get_unit_offset); + + ObjectTypeDB::bind_method(_MD("set_rotation_mode","rotation_mode"),&PathFollow::set_rotation_mode); + ObjectTypeDB::bind_method(_MD("get_rotation_mode"),&PathFollow::get_rotation_mode); + + ObjectTypeDB::bind_method(_MD("set_cubic_interpolation","enable"),&PathFollow::set_cubic_interpolation); + ObjectTypeDB::bind_method(_MD("get_cubic_interpolation"),&PathFollow::get_cubic_interpolation); + + ObjectTypeDB::bind_method(_MD("set_loop","loop"),&PathFollow::set_loop); + ObjectTypeDB::bind_method(_MD("has_loop"),&PathFollow::has_loop); + + BIND_CONSTANT( ROTATION_NONE ); + BIND_CONSTANT( ROTATION_Y ); + BIND_CONSTANT( ROTATION_XY ); + BIND_CONSTANT( ROTATION_XYZ ); + +} + +void PathFollow::set_offset(float p_offset) { + + offset=p_offset; + if (path) + _update_transform(); + _change_notify("offset"); + _change_notify("unit_offset"); + +} + +void PathFollow::set_h_offset(float p_h_offset) { + + h_offset=p_h_offset; + if (path) + _update_transform(); + +} + +float PathFollow::get_h_offset() const { + + return h_offset; +} + +void PathFollow::set_v_offset(float p_v_offset) { + + v_offset=p_v_offset; + if (path) + _update_transform(); + +} + +float PathFollow::get_v_offset() const { + + return v_offset; +} + + +float PathFollow::get_offset() const{ + + return offset; +} + +void PathFollow::set_unit_offset(float p_unit_offset) { + + if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) + set_offset(p_unit_offset*path->get_curve()->get_baked_length()); + +} + +float PathFollow::get_unit_offset() const{ + + if (path && path->get_curve().is_valid() && path->get_curve()->get_baked_length()) + return get_offset()/path->get_curve()->get_baked_length(); + else + return 0; +} + +void PathFollow::set_lookahead(float p_lookahead) { + + lookahead=p_lookahead; + +} + +float PathFollow::get_lookahead() const{ + + return lookahead; +} + +void PathFollow::set_rotation_mode(RotationMode p_rotation_mode) { + + rotation_mode=p_rotation_mode; + _update_transform(); +} + +PathFollow::RotationMode PathFollow::get_rotation_mode() const { + + return rotation_mode; +} + +void PathFollow::set_loop(bool p_loop) { + + loop=p_loop; +} + +bool PathFollow::has_loop() const{ + + return loop; +} + + +PathFollow::PathFollow() { + + offset=0; + h_offset=0; + v_offset=0; + path=NULL; + rotation_mode=ROTATION_XYZ; + cubic=true; + loop=true; + lookahead=0.1; +} diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp index a99964cc54..940a29b5d8 100644 --- a/scene/3d/physics_body.cpp +++ b/scene/3d/physics_body.cpp @@ -92,6 +92,7 @@ void PhysicsBody::remove_collision_exception_with(Node* p_node) { PhysicsServer::get_singleton()->body_remove_collision_exception(get_rid(),physics_body->get_rid()); } + void PhysicsBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_layer_mask","mask"),&PhysicsBody::set_layer_mask); ObjectTypeDB::bind_method(_MD("get_layer_mask"),&PhysicsBody::get_layer_mask); @@ -193,7 +194,7 @@ StaticBody::~StaticBody() { -void RigidBody::_body_enter_scene(ObjectID p_id) { +void RigidBody::_body_enter_tree(ObjectID p_id) { Object *obj = ObjectDB::get_instance(p_id); Node *node = obj ? obj->cast_to<Node>() : NULL; @@ -201,9 +202,9 @@ void RigidBody::_body_enter_scene(ObjectID p_id) { Map<ObjectID,BodyState>::Element *E=contact_monitor->body_map.find(p_id); ERR_FAIL_COND(!E); - ERR_FAIL_COND(E->get().in_scene); + ERR_FAIL_COND(E->get().in_tree); - E->get().in_scene=true; + E->get().in_tree=true; emit_signal(SceneStringNames::get_singleton()->body_enter,node); for(int i=0;i<E->get().shapes.size();i++) { @@ -213,15 +214,15 @@ void RigidBody::_body_enter_scene(ObjectID p_id) { } -void RigidBody::_body_exit_scene(ObjectID p_id) { +void RigidBody::_body_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,BodyState>::Element *E=contact_monitor->body_map.find(p_id); ERR_FAIL_COND(!E); - ERR_FAIL_COND(!E->get().in_scene); - E->get().in_scene=false; + ERR_FAIL_COND(!E->get().in_tree); + E->get().in_tree=false; emit_signal(SceneStringNames::get_singleton()->body_exit,node); for(int i=0;i<E->get().shapes.size();i++) { @@ -245,46 +246,48 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape, if (!E) { E = contact_monitor->body_map.insert(objid,BodyState()); - E->get().rc=0; - E->get().in_scene=node && node->is_inside_scene(); + //E->get().rc=0; + E->get().in_tree=node && node->is_inside_tree(); if (node) { - node->connect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene,make_binds(objid)); - node->connect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene,make_binds(objid)); - if (E->get().in_scene) { + node->connect(SceneStringNames::get_singleton()->enter_tree,this,SceneStringNames::get_singleton()->_body_enter_tree,make_binds(objid)); + node->connect(SceneStringNames::get_singleton()->exit_tree,this,SceneStringNames::get_singleton()->_body_exit_tree,make_binds(objid)); + if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_enter,node); } } } - E->get().rc++; + //E->get().rc++; if (node) E->get().shapes.insert(ShapePair(p_body_shape,p_local_shape)); - if (E->get().in_scene) { + if (E->get().in_tree) { emit_signal(SceneStringNames::get_singleton()->body_enter_shape,objid,node,p_body_shape,p_local_shape); } } else { - E->get().rc--; + //E->get().rc--; if (node) E->get().shapes.erase(ShapePair(p_body_shape,p_local_shape)); - if (E->get().rc==0) { + bool in_tree = E->get().in_tree; + + if (E->get().shapes.empty()) { if (node) { - node->disconnect(SceneStringNames::get_singleton()->enter_scene,this,SceneStringNames::get_singleton()->_body_enter_scene); - node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,SceneStringNames::get_singleton()->_body_exit_scene); - if (E->get().in_scene) + 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); + if (in_tree) emit_signal(SceneStringNames::get_singleton()->body_exit,obj); } contact_monitor->body_map.erase(E); } - if (node && E->get().in_scene) { + if (node && in_tree) { emit_signal(SceneStringNames::get_singleton()->body_exit_shape,objid,obj,p_body_shape,p_local_shape); } @@ -635,6 +638,27 @@ RigidBody::AxisLock RigidBody::get_axis_lock() const { } +Array RigidBody::get_colliding_bodies() const { + + ERR_FAIL_COND_V(!contact_monitor,Array()); + + Array ret; + ret.resize(contact_monitor->body_map.size()); + int idx=0; + for (const Map<ObjectID,BodyState>::Element *E=contact_monitor->body_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; +} + + void RigidBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_mode","mode"),&RigidBody::set_mode); @@ -680,12 +704,14 @@ void RigidBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_able_to_sleep"),&RigidBody::is_able_to_sleep); ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&RigidBody::_direct_state_changed); - ObjectTypeDB::bind_method(_MD("_body_enter_scene"),&RigidBody::_body_enter_scene); - ObjectTypeDB::bind_method(_MD("_body_exit_scene"),&RigidBody::_body_exit_scene); + ObjectTypeDB::bind_method(_MD("_body_enter_tree"),&RigidBody::_body_enter_tree); + ObjectTypeDB::bind_method(_MD("_body_exit_tree"),&RigidBody::_body_exit_tree); ObjectTypeDB::bind_method(_MD("set_axis_lock","axis_lock"),&RigidBody::set_axis_lock); ObjectTypeDB::bind_method(_MD("get_axis_lock"),&RigidBody::get_axis_lock); + ObjectTypeDB::bind_method(_MD("get_colliding_bodies"),&RigidBody::get_colliding_bodies); + BIND_VMETHOD(MethodInfo("_integrate_forces",PropertyInfo(Variant::OBJECT,"state:PhysicsDirectBodyState"))); ADD_PROPERTY( PropertyInfo(Variant::INT,"mode",PROPERTY_HINT_ENUM,"Rigid,Static,Character,Kinematic"),_SCS("set_mode"),_SCS("get_mode")); @@ -790,7 +816,7 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { colliding=false; - ERR_FAIL_COND_V(!is_inside_scene(),Vector3()); + ERR_FAIL_COND_V(!is_inside_tree(),Vector3()); PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space()); ERR_FAIL_COND_V(!dss,Vector3()); const int max_shapes=32; @@ -827,6 +853,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { //motion recover for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; if (dss->collide_shape(get_shape(i)->get_rid(), get_global_transform() * get_shape_transform(i),m,sr,max_shapes,res_shapes,exclude,get_layer_mask(),mask)) { collided=true; @@ -905,6 +933,8 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; float lsafe,lunsafe; PhysicsDirectSpaceState::ShapeRestInfo lrest; @@ -965,6 +995,7 @@ Vector3 KinematicBody::move(const Vector3& p_motion) { normal=rest.normal; collider=rest.collider_id; collider_vel=rest.linear_velocity; + collider_shape=rest.shape; } } @@ -986,7 +1017,7 @@ Vector3 KinematicBody::move_to(const Vector3& p_position) { bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) { - ERR_FAIL_COND_V(!is_inside_scene(),false); + ERR_FAIL_COND_V(!is_inside_tree(),false); PhysicsDirectSpaceState *dss = PhysicsServer::get_singleton()->space_get_direct_state(get_world()->get_space()); ERR_FAIL_COND_V(!dss,false); @@ -1015,6 +1046,8 @@ bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) { //fill exclude list.. for(int i=0;i<get_shape_count();i++) { + if (is_shape_set_as_trigger(i)) + continue; bool col = dss->intersect_shape(get_shape(i)->get_rid(), xform * get_shape_transform(i),0,NULL,0,exclude,get_layer_mask(),mask); if (col) @@ -1026,7 +1059,7 @@ bool KinematicBody::can_move_to(const Vector3& p_position, bool p_discrete) { bool KinematicBody::is_colliding() const { - ERR_FAIL_COND_V(!is_inside_scene(),false); + ERR_FAIL_COND_V(!is_inside_tree(),false); return colliding; } @@ -1053,7 +1086,12 @@ ObjectID KinematicBody::get_collider() const { ERR_FAIL_COND_V(!colliding,0); return collider; } +int KinematicBody::get_collider_shape() const { + ERR_FAIL_COND_V(!colliding,-1); + return collider_shape; + +} void KinematicBody::set_collide_with_static_bodies(bool p_enable) { collide_static=p_enable; @@ -1117,6 +1155,7 @@ void KinematicBody::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_normal"),&KinematicBody::get_collision_normal); ObjectTypeDB::bind_method(_MD("get_collider_velocity"),&KinematicBody::get_collider_velocity); ObjectTypeDB::bind_method(_MD("get_collider:Object"),&KinematicBody::_get_collider); + ObjectTypeDB::bind_method(_MD("get_collider_shape"),&KinematicBody::get_collider_shape); ObjectTypeDB::bind_method(_MD("set_collide_with_static_bodies","enable"),&KinematicBody::set_collide_with_static_bodies); @@ -1153,6 +1192,7 @@ KinematicBody::KinematicBody() : PhysicsBody(PhysicsServer::BODY_MODE_KINEMATIC) colliding=false; collider=0; margin=0.001; + collider_shape=0; } KinematicBody::~KinematicBody() { diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h index 442921302e..beec01ff3a 100644 --- a/scene/3d/physics_body.h +++ b/scene/3d/physics_body.h @@ -56,6 +56,8 @@ public: void add_collision_exception_with(Node* p_node); //must be physicsbody void remove_collision_exception_with(Node* p_node); + + PhysicsBody(); }; @@ -162,8 +164,8 @@ private: }; struct BodyState { - int rc; - bool in_scene; + //int rc; + bool in_tree; VSet<ShapePair> shapes; }; @@ -176,8 +178,8 @@ private: ContactMonitor *contact_monitor; - void _body_enter_scene(ObjectID p_id); - void _body_exit_scene(ObjectID p_id); + void _body_enter_tree(ObjectID p_id); + void _body_exit_tree(ObjectID p_id); void _body_inout(int p_status, ObjectID p_instance, int p_body_shape,int p_local_shape); @@ -236,6 +238,7 @@ public: void set_axis_lock(AxisLock p_lock); AxisLock get_axis_lock() const; + Array get_colliding_bodies() const; void apply_impulse(const Vector3& p_pos, const Vector3& p_impulse); @@ -266,6 +269,8 @@ class KinematicBody : public PhysicsBody { Vector3 normal; Vector3 collider_vel; ObjectID collider; + int collider_shape; + Variant _get_collider() const; @@ -291,6 +296,7 @@ public: Vector3 get_collision_normal() const; Vector3 get_collider_velocity() const; ObjectID get_collider() const; + int get_collider_shape() const; void set_collide_with_static_bodies(bool p_enable); bool can_collide_with_static_bodies() const; diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp index 341b02314d..8d9257a273 100644 --- a/scene/3d/physics_joint.cpp +++ b/scene/3d/physics_joint.cpp @@ -42,7 +42,7 @@ void Joint::_update_joint(bool p_only_free) { bb=RID(); } - if (p_only_free || !is_inside_scene()) + if (p_only_free || !is_inside_tree()) return; Node *node_a = has_node( get_node_a() ) ? get_node( get_node_a() ) : (Node*)NULL; @@ -66,6 +66,9 @@ void Joint::_update_joint(bool p_only_free) { joint = _configure_joint(body_a,body_b); + if (joint.is_valid()) + PhysicsServer::get_singleton()->joint_set_solver_priority(joint,solver_priority); + if (body_b && joint.is_valid()) { ba=body_a->get_rid(); @@ -107,6 +110,20 @@ NodePath Joint::get_node_b() const{ } +void Joint::set_solver_priority(int p_priority) { + + solver_priority=p_priority; + if (joint.is_valid()) + PhysicsServer::get_singleton()->joint_set_solver_priority(joint,solver_priority); + +} + +int Joint::get_solver_priority() const { + + return solver_priority; +} + + void Joint::_notification(int p_what) { switch(p_what) { @@ -114,11 +131,9 @@ void Joint::_notification(int p_what) { case NOTIFICATION_READY: { _update_joint(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (joint.is_valid()) { _update_joint(true); - - PhysicsServer::get_singleton()->free(joint); joint=RID(); } @@ -138,9 +153,13 @@ void Joint::_bind_methods() { ObjectTypeDB::bind_method( _MD("set_node_b","node"), &Joint::set_node_b ); ObjectTypeDB::bind_method( _MD("get_node_b"), &Joint::get_node_b ); + ObjectTypeDB::bind_method( _MD("set_solver_priority","priority"), &Joint::set_solver_priority ); + ObjectTypeDB::bind_method( _MD("get_solver_priority"), &Joint::get_solver_priority ); ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "nodes/node_a"), _SCS("set_node_a"),_SCS("get_node_a") ); ADD_PROPERTY( PropertyInfo( Variant::NODE_PATH, "nodes/node_b"), _SCS("set_node_b"),_SCS("get_node_b") ); + ADD_PROPERTY( PropertyInfo( Variant::INT, "solver/priority",PROPERTY_HINT_RANGE,"1,8,1"), _SCS("set_solver_priority"),_SCS("get_solver_priority") ); + } @@ -148,7 +167,7 @@ void Joint::_bind_methods() { Joint::Joint() { - + solver_priority=1; } diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h index 6daa06da2b..32bec1bd6f 100644 --- a/scene/3d/physics_joint.h +++ b/scene/3d/physics_joint.h @@ -44,6 +44,8 @@ class Joint : public Spatial { NodePath a; NodePath b; + int solver_priority; + protected: @@ -62,6 +64,9 @@ public: void set_node_b(const NodePath& p_node_b); NodePath get_node_b() const; + void set_solver_priority(int p_priority); + int get_solver_priority() const; + RID get_joint() const { return joint; } Joint(); diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp index b3378c7698..a30a23aa53 100644 --- a/scene/3d/proximity_group.cpp +++ b/scene/3d/proximity_group.cpp @@ -119,7 +119,7 @@ void ProximityGroup::_notification(int what) { switch (what) { - case NOTIFICATION_EXIT_SCENE: + case NOTIFICATION_EXIT_TREE: ++group_version; clear_groups(); break; @@ -135,7 +135,7 @@ void ProximityGroup::broadcast(String p_name, Variant p_params) { E = groups.front(); while (E) { - get_scene()->call_group(SceneMainLoop::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params); + get_tree()->call_group(SceneTree::GROUP_CALL_DEFAULT, E->key(), "_proximity_group_broadcast", p_name, p_params); E = E->next(); }; diff --git a/scene/3d/quad.cpp b/scene/3d/quad.cpp index 78dd56141c..8ee232fef4 100644 --- a/scene/3d/quad.cpp +++ b/scene/3d/quad.cpp @@ -31,7 +31,7 @@ void Quad::_update() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; Vector3 normal; @@ -171,14 +171,14 @@ void Quad::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (pending_update) _update(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { pending_update=true; diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp index e36e2da14f..639a86e759 100644 --- a/scene/3d/ray_cast.cpp +++ b/scene/3d/ray_cast.cpp @@ -33,7 +33,7 @@ void RayCast::set_cast_to(const Vector3& p_point) { cast_to=p_point; - if (is_inside_scene() && get_scene()->is_editor_hint()) + if (is_inside_tree() && get_tree()->is_editor_hint()) update_gizmo(); } @@ -72,7 +72,7 @@ Vector3 RayCast::get_collision_normal() const{ void RayCast::set_enabled(bool p_enabled) { enabled=p_enabled; - if (is_inside_scene() && !get_scene()->is_editor_hint()) + if (is_inside_tree() && !get_tree()->is_editor_hint()) set_fixed_process(p_enabled); if (!p_enabled) collided=false; @@ -91,35 +91,22 @@ void RayCast::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { - if (enabled && !get_scene()->is_editor_hint()) { + if (enabled && !get_tree()->is_editor_hint()) { set_fixed_process(true); - Node *p = get_parent(); - while( p && p->cast_to<Spatial>() ) { - - CollisionObject *co = p->cast_to<CollisionObject>(); - if (co) { - - exception=co->get_rid(); - exceptions.insert(exception); - } - - p=p->get_parent(); - } } else set_fixed_process(false); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (enabled) { set_fixed_process(false); } - exceptions.erase(exception); } break; case NOTIFICATION_FIXED_PROCESS: { @@ -143,7 +130,7 @@ void RayCast::_notification(int p_what) { PhysicsDirectSpaceState::RayResult rr; - if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exceptions)) { + if (dss->intersect_ray(gt.get_origin(),gt.xform(to),rr,exclude)) { collided=true; against=rr.collider_id; @@ -160,6 +147,41 @@ void RayCast::_notification(int p_what) { } } +void RayCast::add_exception_rid(const RID& p_rid) { + + exclude.insert(p_rid); +} + +void RayCast::add_exception(const Object* p_object){ + + ERR_FAIL_NULL(p_object); + CollisionObject *co=((Object*)p_object)->cast_to<CollisionObject>(); + if (!co) + return; + add_exception_rid(co->get_rid()); +} + +void RayCast::remove_exception_rid(const RID& p_rid) { + + exclude.erase(p_rid); +} + +void RayCast::remove_exception(const Object* p_object){ + + ERR_FAIL_NULL(p_object); + CollisionObject *co=((Object*)p_object)->cast_to<CollisionObject>(); + if (!co) + return; + remove_exception_rid(co->get_rid()); +} + + +void RayCast::clear_exceptions(){ + + exclude.clear(); +} + + void RayCast::_bind_methods() { @@ -176,6 +198,14 @@ void RayCast::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_collision_point"),&RayCast::get_collision_point); ObjectTypeDB::bind_method(_MD("get_collision_normal"),&RayCast::get_collision_normal); + ObjectTypeDB::bind_method(_MD("add_exception_rid","rid"),&RayCast::add_exception_rid); + ObjectTypeDB::bind_method(_MD("add_exception","node"),&RayCast::add_exception); + + ObjectTypeDB::bind_method(_MD("remove_exception_rid","rid"),&RayCast::remove_exception_rid); + ObjectTypeDB::bind_method(_MD("remove_exception","node"),&RayCast::remove_exception); + + ObjectTypeDB::bind_method(_MD("clear_exceptions"),&RayCast::clear_exceptions); + ADD_PROPERTY(PropertyInfo(Variant::BOOL,"enabled"),_SCS("set_enabled"),_SCS("is_enabled")); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3,"cast_to"),_SCS("set_cast_to"),_SCS("get_cast_to")); } diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h index 96606b1628..0239c61b67 100644 --- a/scene/3d/ray_cast.h +++ b/scene/3d/ray_cast.h @@ -45,8 +45,7 @@ class RayCast : public Spatial { Vector3 cast_to; - RID exception; - Set<RID> exceptions; + Set<RID> exclude; protected: @@ -66,6 +65,12 @@ public: Vector3 get_collision_point() const; Vector3 get_collision_normal() const; + void add_exception_rid(const RID& p_rid); + void add_exception(const Object* p_object); + void remove_exception_rid(const RID& p_rid); + void remove_exception(const Object* p_object); + void clear_exceptions(); + RayCast(); }; diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp index fa1d3ecf6b..3f9e6c7f13 100644 --- a/scene/3d/room_instance.cpp +++ b/scene/3d/room_instance.cpp @@ -147,7 +147,7 @@ void Room::set_room( const Ref<RoomBounds>& p_room ) { set_base(RID()); } - if (!is_inside_scene()) + if (!is_inside_tree()) return; diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp index 858ee4e4ad..f53ee7d6bf 100644 --- a/scene/3d/skeleton.cpp +++ b/scene/3d/skeleton.cpp @@ -237,6 +237,21 @@ Transform Skeleton::get_bone_transform(int p_bone) const { return bones[p_bone].pose_global * bones[p_bone].rest_global_inverse; } + +void Skeleton::set_bone_global_pose(int p_bone,const Transform& p_pose) { + + ERR_FAIL_INDEX(p_bone,bones.size()); + if (bones[p_bone].parent==-1) { + + set_bone_pose(p_bone,bones[p_bone].rest_global_inverse * p_pose); //fast + } else { + + set_bone_pose(p_bone, bones[p_bone].rest.affine_inverse() * (get_bone_global_pose(bones[p_bone].parent).affine_inverse() * p_pose)); //slow + + } + +} + Transform Skeleton::get_bone_global_pose(int p_bone) const { ERR_FAIL_INDEX_V(p_bone,bones.size(),Transform()); @@ -389,7 +404,7 @@ void Skeleton::clear_bones() { void Skeleton::set_bone_pose(int p_bone, const Transform& p_pose) { ERR_FAIL_INDEX( p_bone, bones.size() ); - ERR_FAIL_COND( !is_inside_scene() ); + ERR_FAIL_COND( !is_inside_tree() ); bones[p_bone].pose=p_pose; @@ -427,7 +442,7 @@ void Skeleton::_make_dirty() { if (dirty) return; - if (!is_inside_scene()) { + if (!is_inside_tree()) { dirty=true; return; } @@ -519,6 +534,7 @@ void Skeleton::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_bone_pose","bone_idx"),&Skeleton::get_bone_pose); ObjectTypeDB::bind_method(_MD("set_bone_pose","bone_idx","pose"),&Skeleton::set_bone_pose); + ObjectTypeDB::bind_method(_MD("set_bone_global_pose","bone_idx","pose"),&Skeleton::set_bone_global_pose); ObjectTypeDB::bind_method(_MD("get_bone_global_pose","bone_idx"),&Skeleton::get_bone_global_pose); ObjectTypeDB::bind_method(_MD("get_bone_custom_pose","bone_idx"),&Skeleton::get_bone_custom_pose); diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h index 3e0ab0afd7..c61946a4c7 100644 --- a/scene/3d/skeleton.h +++ b/scene/3d/skeleton.h @@ -118,6 +118,8 @@ public: Transform get_bone_transform(int p_bone) const; Transform get_bone_global_pose(int p_bone) const; + void set_bone_global_pose(int p_bone,const Transform& p_pose); + void set_bone_enabled(int p_bone, bool p_enabled); bool is_bone_enabled(int p_bone) const; diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp index d304095d33..a5b009823c 100644 --- a/scene/3d/spatial.cpp +++ b/scene/3d/spatial.cpp @@ -76,7 +76,7 @@ void Spatial::_notify_dirty() { if (!data.ignore_notification && !xform_change.in_list()) { - get_scene()->xform_change_list.add(&xform_change); + get_tree()->xform_change_list.add(&xform_change); } } @@ -91,7 +91,7 @@ void Spatial::_update_local_transform() const { } void Spatial::_propagate_transform_changed(Spatial *p_origin) { - if (!is_inside_scene()) { + if (!is_inside_tree()) { return; } @@ -110,7 +110,7 @@ void Spatial::_propagate_transform_changed(Spatial *p_origin) { if (!data.ignore_notification && !xform_change.in_list()) { - get_scene()->xform_change_list.add(&xform_change); + get_tree()->xform_change_list.add(&xform_change); } data.dirty|=DIRTY_GLOBAL; @@ -121,7 +121,7 @@ void Spatial::_propagate_transform_changed(Spatial *p_origin) { void Spatial::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { Node *p = get_parent(); if (p) @@ -132,7 +132,7 @@ void Spatial::_notification(int p_what) { else data.C=NULL; - if (data.toplevel && !get_scene()->is_editor_hint()) { + if (data.toplevel && !get_tree()->is_editor_hint()) { if (data.parent) { data.local_transform = data.parent->get_global_transform() * get_transform(); @@ -147,11 +147,11 @@ void Spatial::_notification(int p_what) { notification(NOTIFICATION_ENTER_WORLD); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { notification(NOTIFICATION_EXIT_WORLD,true); if (xform_change.in_list()) - get_scene()->xform_change_list.remove(&xform_change); + get_tree()->xform_change_list.remove(&xform_change); if (data.C) data.parent->data.children.erase(data.C); data.parent=NULL; @@ -177,10 +177,10 @@ void Spatial::_notification(int p_what) { get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_enter_world,NULL,0); } #ifdef TOOLS_ENABLED - if (get_scene()->is_editor_hint()) { + if (get_tree()->is_editor_hint()) { // get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); - get_scene()->call_group(0,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); + get_tree()->call_group(0,SceneStringNames::get_singleton()->_spatial_editor_group,SceneStringNames::get_singleton()->_request_gizmo,this); if (!data.gizmo_disabled) { if (data.gizmo.is_valid()) @@ -257,7 +257,7 @@ Transform Spatial::get_transform() const { } Transform Spatial::get_global_transform() const { - ERR_FAIL_COND_V(!is_inside_scene(), Transform()); + ERR_FAIL_COND_V(!is_inside_tree(), Transform()); if (data.dirty & DIRTY_GLOBAL) { @@ -460,7 +460,7 @@ void Spatial::set_as_toplevel(bool p_enabled) { if (data.toplevel==p_enabled) return; - if (is_inside_scene() && !get_scene()->is_editor_hint()) { + if (is_inside_tree() && !get_tree()->is_editor_hint()) { if (p_enabled) set_transform(get_global_transform()); @@ -537,7 +537,7 @@ void Spatial::show() { data.visible=true; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (!data.parent || is_visible()) { diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h index 7036ef63ca..49ecf5779b 100644 --- a/scene/3d/spatial.h +++ b/scene/3d/spatial.h @@ -130,7 +130,7 @@ public: enum { - NOTIFICATION_TRANSFORM_CHANGED=SceneMainLoop::NOTIFICATION_TRANSFORM_CHANGED, + NOTIFICATION_TRANSFORM_CHANGED=SceneTree::NOTIFICATION_TRANSFORM_CHANGED, NOTIFICATION_ENTER_WORLD=41, NOTIFICATION_EXIT_WORLD=42, NOTIFICATION_VISIBILITY_CHANGED=43, diff --git a/scene/3d/spatial_sample_player.cpp b/scene/3d/spatial_sample_player.cpp index b4a5d3bc1b..6dc71e06ad 100644 --- a/scene/3d/spatial_sample_player.cpp +++ b/scene/3d/spatial_sample_player.cpp @@ -103,6 +103,7 @@ void SpatialSamplePlayer::_notification(int p_what) { void SpatialSamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) { library=p_library; + _change_notify(); } Ref<SampleLibrary> SpatialSamplePlayer::get_sample_library() const { diff --git a/scene/3d/spatial_stream_player.cpp b/scene/3d/spatial_stream_player.cpp index 25448498cb..51009662d6 100644 --- a/scene/3d/spatial_stream_player.cpp +++ b/scene/3d/spatial_stream_player.cpp @@ -74,7 +74,7 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const { void SpatialStreamPlayer::play() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (stream.is_null()) return; @@ -89,7 +89,7 @@ void SpatialStreamPlayer::play() { void SpatialStreamPlayer::stop() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (stream.is_null()) return; diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp index 334a15e724..35f6523c6a 100644 --- a/scene/3d/sprite_3d.cpp +++ b/scene/3d/sprite_3d.cpp @@ -37,7 +37,7 @@ void SpriteBase3D::_propagate_color_changed() { void SpriteBase3D::_notification(int p_what) { - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { if (!pending_update) _im_update(); @@ -52,7 +52,7 @@ void SpriteBase3D::_notification(int p_what) { } } - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { if (parent_sprite) { @@ -275,6 +275,9 @@ void SpriteBase3D::_bind_methods() { BIND_CONSTANT( ALPHA_CUT_DISABLED ); BIND_CONSTANT( ALPHA_CUT_DISCARD ); BIND_CONSTANT( ALPHA_CUT_OPAQUE_PREPASS ); + + + } @@ -494,6 +497,8 @@ void Sprite3D::set_frame(int p_frame) { frame=p_frame; _queue_update(); + emit_signal(SceneStringNames::get_singleton()->frame_changed); + } int Sprite3D::get_frame() const { @@ -579,6 +584,8 @@ void Sprite3D::_bind_methods() { 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_SIGNAL(MethodInfo("frame_changed")); + } Sprite3D::Sprite3D() { @@ -722,6 +729,8 @@ void AnimatedSprite3D::_bind_methods(){ ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE,"SpriteFrames"), _SCS("set_sprite_frames"),_SCS("get_sprite_frames")); ADD_PROPERTY( PropertyInfo( Variant::INT, "frame"), _SCS("set_frame"),_SCS("get_frame")); + ADD_SIGNAL(MethodInfo("frame_changed")); + } @@ -764,6 +773,7 @@ void AnimatedSprite3D::set_frame(int p_frame){ frame=p_frame; _queue_update(); + emit_signal(SceneStringNames::get_singleton()->frame_changed); } int AnimatedSprite3D::get_frame() const{ diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp index 07abd1dcd2..ba30c118f0 100644 --- a/scene/3d/vehicle_body.cpp +++ b/scene/3d/vehicle_body.cpp @@ -57,7 +57,7 @@ public: void VehicleWheel::_notification(int p_what) { - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { if (!get_parent()) return; @@ -73,7 +73,7 @@ void VehicleWheel::_notification(int p_what) { m_wheelAxleCS = get_transform().basis.get_axis(Vector3::AXIS_X).normalized(); } - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { if (!get_parent()) return; @@ -179,7 +179,7 @@ void VehicleWheel::set_damping_compression(float p_value){ } float VehicleWheel::get_damping_compression() const{ - return m_wheelsDampingRelaxation; + return m_wheelsDampingCompression; } void VehicleWheel::set_damping_relaxation(float p_value){ @@ -745,11 +745,12 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) { { if (engine_force != 0.f) { - rollingFriction = engine_force* s->get_step(); + rollingFriction = -engine_force* s->get_step(); } else { real_t defaultRollingFrictionImpulse = 0.f; - real_t maxImpulse = wheelInfo.m_brake ? wheelInfo.m_brake : defaultRollingFrictionImpulse; + float cbrake = MAX(wheelInfo.m_brake,brake); + real_t maxImpulse = cbrake ? cbrake : defaultRollingFrictionImpulse; btVehicleWheelContactPoint contactPt(s,wheelInfo.m_raycastInfo.m_groundObject,wheelInfo.m_raycastInfo.m_contactPointWS,m_forwardWS[wheel],maxImpulse); rollingFriction = _calc_rolling_friction(contactPt); } @@ -1009,9 +1010,9 @@ void VehicleBody::_bind_methods(){ ObjectTypeDB::bind_method(_MD("_direct_state_changed"),&VehicleBody::_direct_state_changed); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/engine_force",PROPERTY_HINT_RANGE,"0.01,1024.0,0.01"),_SCS("set_engine_force"),_SCS("get_engine_force")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/brake",PROPERTY_HINT_RANGE,"0.01,1024.0,0.01"),_SCS("set_brake"),_SCS("get_brake")); - ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/steering",PROPERTY_HINT_RANGE,"0.01,1024.0,0.01"),_SCS("set_steering"),_SCS("get_steering")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/engine_force",PROPERTY_HINT_RANGE,"0.00,1024.0,0.01"),_SCS("set_engine_force"),_SCS("get_engine_force")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/brake",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_brake"),_SCS("get_brake")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"motion/steering",PROPERTY_HINT_RANGE,"-180,180.0,0.01"),_SCS("set_steering"),_SCS("get_steering")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/mass",PROPERTY_HINT_RANGE,"0.01,65536,0.01"),_SCS("set_mass"),_SCS("get_mass")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"body/friction",PROPERTY_HINT_RANGE,"0.01,1,0.01"),_SCS("set_friction"),_SCS("get_friction")); diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp index 60e311cefe..d4ef2931e9 100644 --- a/scene/3d/visibility_notifier.cpp +++ b/scene/3d/visibility_notifier.cpp @@ -183,7 +183,7 @@ void VisibilityEnabler::_find_nodes(Node* p_node) { if (add) { - p_node->connect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); + p_node->connect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed",varray(p_node),CONNECT_ONESHOT); nodes[p_node]=meta; _change_node_state(p_node,false); } @@ -200,9 +200,9 @@ void VisibilityEnabler::_find_nodes(Node* p_node) { void VisibilityEnabler::_notification(int p_what){ - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) return; @@ -215,9 +215,9 @@ void VisibilityEnabler::_notification(int p_what){ } - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) return; @@ -228,7 +228,7 @@ void VisibilityEnabler::_notification(int p_what){ if (!visible) _change_node_state(E->key(),true); - E->key()->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + E->key()->disconnect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed"); } nodes.clear(); @@ -271,7 +271,7 @@ void VisibilityEnabler::_node_removed(Node* p_node) { if (!visible) _change_node_state(p_node,true); - p_node->disconnect(SceneStringNames::get_singleton()->exit_scene,this,"_node_removed"); + p_node->disconnect(SceneStringNames::get_singleton()->exit_tree,this,"_node_removed"); nodes.erase(p_node); } diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp index af535e139f..a82c69e67f 100644 --- a/scene/3d/visual_instance.cpp +++ b/scene/3d/visual_instance.cpp @@ -50,17 +50,24 @@ void VisualInstance::_notification(int p_what) { // CHECK ROOM Spatial * parent = get_parent_spatial(); Room *room=NULL; + bool is_geom = cast_to<GeometryInstance>(); while(parent) { room = parent->cast_to<Room>(); if (room) break; - else - parent=parent->get_parent_spatial(); + + if (is_geom && parent->cast_to<BakedLightSampler>()) { + VS::get_singleton()->instance_geometry_set_baked_light_sampler(get_instance(),parent->cast_to<BakedLightSampler>()->get_instance()); + break; + } + + parent=parent->get_parent_spatial(); } + if (room) { VisualServer::get_singleton()->instance_set_room(instance,room->get_instance()); @@ -85,6 +92,7 @@ void VisualInstance::_notification(int p_what) { VisualServer::get_singleton()->instance_set_scenario( instance, RID() ); VisualServer::get_singleton()->instance_set_room(instance,RID()); VisualServer::get_singleton()->instance_attach_skeleton( instance, RID() ); + VS::get_singleton()->instance_geometry_set_baked_light_sampler(instance, RID() ); } break; @@ -249,7 +257,7 @@ void GeometryInstance::_find_baked_light() { void GeometryInstance::_update_visibility() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; _change_notify("geometry/visible"); @@ -351,13 +359,13 @@ void GeometryInstance::_bind_methods() { GeometryInstance::GeometryInstance() { draw_begin=0; draw_end=0; + for(int i=0;i<FLAG_MAX;i++) { + flags[i]=false; + } + flags[FLAG_VISIBLE]=true; flags[FLAG_CAST_SHADOW]=true; flags[FLAG_RECEIVE_SHADOWS]=true; - flags[FLAG_BILLBOARD]=false; - flags[FLAG_BILLBOARD_FIX_Y]=false; - flags[FLAG_DEPH_SCALE]=false; - flags[FLAG_VISIBLE_IN_ALL_ROOMS]=false; baked_light_instance=NULL; baked_light_texture_id=0; VS::get_singleton()->instance_geometry_set_baked_light_texture_index(get_instance(),0); diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h index bbb49a2e78..e9fefe1ba0 100644 --- a/scene/3d/visual_instance.h +++ b/scene/3d/visual_instance.h @@ -47,6 +47,7 @@ class VisualInstance : public Spatial { RID _get_visual_instance_rid() const; + protected: diff --git a/scene/SCsub b/scene/SCsub index 28fb358106..8c4f0499c4 100644 --- a/scene/SCsub +++ b/scene/SCsub @@ -15,7 +15,7 @@ SConscript('resources/SCsub'); SConscript('io/SCsub'); -lib = env.Library("scene",env.scene_sources, LIBSUFFIX=env['platform_libsuffix']) +lib = env.Library("scene",env.scene_sources) env.Prepend(LIBS=[lib]) diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp index 38cfe0d8a9..46eb8d7e88 100644 --- a/scene/animation/animation_cache.cpp +++ b/scene/animation/animation_cache.cpp @@ -30,7 +30,7 @@ -void AnimationCache::_node_exit_scene(Node *p_node) { +void AnimationCache::_node_exit_tree(Node *p_node) { //it is one shot, so it disconnects upon arrival @@ -59,7 +59,7 @@ void AnimationCache::_clear_cache() { while(connected_nodes.size()) { - connected_nodes.front()->get()->disconnect("exit_scene",this,"_node_exit_scene"); + connected_nodes.front()->get()->disconnect("exit_tree",this,"_node_exit_tree"); connected_nodes.erase(connected_nodes.front()); } path_cache.clear();; @@ -73,7 +73,7 @@ void AnimationCache::_update_cache() { cache_valid=false; ERR_FAIL_COND(!root); - ERR_FAIL_COND(!root->is_inside_scene()); + ERR_FAIL_COND(!root->is_inside_tree()); ERR_FAIL_COND(animation.is_null()); for(int i=0;i<animation->get_track_count();i++) { @@ -206,7 +206,7 @@ void AnimationCache::_update_cache() { if (!connected_nodes.has(path.node)) { connected_nodes.insert(path.node); - path.node->connect("exit_scene",this,"_node_exit_scene",Node::make_binds(path.node),CONNECT_ONESHOT); + path.node->connect("exit_tree",this,"_node_exit_tree",Node::make_binds(path.node),CONNECT_ONESHOT); } @@ -368,7 +368,7 @@ void AnimationCache::set_animation(const Ref<Animation>& p_animation) { void AnimationCache::_bind_methods() { - ObjectTypeDB::bind_method(_MD("_node_exit_scene"),&AnimationCache::_node_exit_scene); + ObjectTypeDB::bind_method(_MD("_node_exit_tree"),&AnimationCache::_node_exit_tree); ObjectTypeDB::bind_method(_MD("_animation_changed"),&AnimationCache::_animation_changed); } diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h index 72ee8f1860..d00b122faa 100644 --- a/scene/animation/animation_cache.h +++ b/scene/animation/animation_cache.h @@ -58,7 +58,7 @@ class AnimationCache : public Object { bool cache_dirty; bool cache_valid; - void _node_exit_scene(Node *p_node); + void _node_exit_tree(Node *p_node); void _clear_cache(); void _update_cache(); diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp index 030f3f27e0..f9d36138a2 100644 --- a/scene/animation/animation_player.cpp +++ b/scene/animation/animation_player.cpp @@ -180,12 +180,16 @@ void AnimationPlayer::_get_property_list( List<PropertyInfo> *p_list) const { } +void AnimationPlayer::advance(float p_time) { + + _animation_process( p_time ); +} void AnimationPlayer::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (!processing) { //make sure that a previous process state was not saved @@ -198,7 +202,7 @@ void AnimationPlayer::_notification(int p_what) { } break; case NOTIFICATION_READY: { - if (!get_scene()->is_editor_hint() && animation_set.has(autoplay)) { + if (!get_tree()->is_editor_hint() && animation_set.has(autoplay)) { play(autoplay); } } break; @@ -217,7 +221,7 @@ void AnimationPlayer::_notification(int p_what) { if (processing) _animation_process( get_fixed_process_delta_time() ); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { stop_all(); clear_caches(); @@ -257,8 +261,8 @@ void AnimationPlayer::_generate_node_caches(AnimationData* p_anim) { } { - if (!child->is_connected("exit_scene",this,"_node_removed")) - child->connect("exit_scene",this,"_node_removed",make_binds(child),CONNECT_ONESHOT); + if (!child->is_connected("exit_tree",this,"_node_removed")) + child->connect("exit_tree",this,"_node_removed",make_binds(child),CONNECT_ONESHOT); } TrackNodeCacheKey key; @@ -344,7 +348,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p Animation *a=p_anim->animation.operator->(); - bool can_call = is_inside_scene() && !get_scene()->is_editor_hint(); + bool can_call = is_inside_tree() && !get_tree()->is_editor_hint(); for (int i=0;i<a->get_track_count();i++) { @@ -370,7 +374,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData* p_anim,float p Error err = a->transform_track_interpolate(i,p_time,&loc,&rot,&scale); - ERR_CONTINUE(err!=OK); //used for testing, should be removed + //ERR_CONTINUE(err!=OK); //used for testing, should be removed if (err!=OK) @@ -918,12 +922,12 @@ void AnimationPlayer::play(const StringName& p_name, float p_custom_blend, float _set_process(true); // always process when starting an animation playing = true; - if (is_inside_scene() && get_scene()->is_editor_hint()) + if (is_inside_tree() && get_tree()->is_editor_hint()) return; // no next in this case StringName next=animation_get_next(p_name); - if (next!=StringName()) { + if (next!=StringName() && animation_set.has(next)) { queue(next); } } @@ -1174,6 +1178,19 @@ NodePath AnimationPlayer::get_root() const { return root; } +void AnimationPlayer::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const { + + String pf = p_function; + if (p_function=="play" || p_function=="remove_animation" || p_function=="has_animation" || p_function=="queue") { + List<StringName> al; + get_animation_list(&al); + for (List<StringName>::Element *E=al.front();E;E=E->next()) { + + r_options->push_back("\""+String(E->get())+"\""); + } + } + Node::get_argument_options(p_function,p_idx,r_options); +} void AnimationPlayer::_bind_methods() { @@ -1227,6 +1244,8 @@ void AnimationPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_current_animation_pos"),&AnimationPlayer::get_current_animation_pos); ObjectTypeDB::bind_method(_MD("get_current_animation_length"),&AnimationPlayer::get_current_animation_length); + ObjectTypeDB::bind_method(_MD("advance","delta"),&AnimationPlayer::advance); + ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_animation_process_mode"), _SCS("get_animation_process_mode")); ADD_PROPERTY( PropertyInfo( Variant::REAL, "playback/default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), _SCS("set_default_blend_time"), _SCS("get_default_blend_time")); diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h index 51c000d4d8..8ac5d96bf3 100644 --- a/scene/animation/animation_player.h +++ b/scene/animation/animation_player.h @@ -283,10 +283,15 @@ public: float get_current_animation_pos() const; float get_current_animation_length() const; + void advance(float p_time); + void set_root(const NodePath& p_root); NodePath get_root() const; void clear_caches(); ///< must be called by hand if an animation was modified after added + + void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; + AnimationPlayer(); ~AnimationPlayer(); diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp index 2d1821bc5c..5172907d18 100644 --- a/scene/animation/animation_tree_player.cpp +++ b/scene/animation/animation_tree_player.cpp @@ -83,7 +83,8 @@ bool AnimationTreePlayer::_set(const StringName& p_name, const Variant& p_value) ERR_FAIL_COND_V(nt==NODE_MAX,false); - add_node(nt,id); + if (nt!=NODE_OUTPUT) + add_node(nt,id); node_set_pos(id,pos); @@ -1586,7 +1587,7 @@ void AnimationTreePlayer::_update_sources() { if (master==NodePath()) return; - if (!is_inside_scene()) + if (!is_inside_tree()) return; Node *m = get_node(master); @@ -1662,7 +1663,7 @@ void AnimationTreePlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("node_get_type","id"),&AnimationTreePlayer::node_get_type); ObjectTypeDB::bind_method(_MD("node_get_input_count","id"),&AnimationTreePlayer::node_get_input_count); - ObjectTypeDB::bind_method(_MD("node_get_input_sourcre","id","idx"),&AnimationTreePlayer::node_get_input_source); + ObjectTypeDB::bind_method(_MD("node_get_input_source","id","idx"),&AnimationTreePlayer::node_get_input_source); ObjectTypeDB::bind_method(_MD("animation_node_set_animation","id","animation:Animation"),&AnimationTreePlayer::animation_node_set_animation); ObjectTypeDB::bind_method(_MD("animation_node_get_animation:Animation","id"),&AnimationTreePlayer::animation_node_get_animation); diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp index 7e7d57c3c2..f668e52590 100644 --- a/scene/animation/tween.cpp +++ b/scene/animation/tween.cpp @@ -75,7 +75,7 @@ void Tween::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (!processing) { //make sure that a previous process state was not saved @@ -102,7 +102,7 @@ void Tween::_notification(int p_what) { if (processing) _tween_process( get_fixed_process_delta_time() ); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { stop_all(); } break; @@ -124,32 +124,34 @@ void Tween::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_tween_process_mode"),&Tween::get_tween_process_mode); ObjectTypeDB::bind_method(_MD("start"),&Tween::start ); - ObjectTypeDB::bind_method(_MD("reset","node","key"),&Tween::reset ); + ObjectTypeDB::bind_method(_MD("reset","object","key"),&Tween::reset ); ObjectTypeDB::bind_method(_MD("reset_all"),&Tween::reset_all ); - ObjectTypeDB::bind_method(_MD("stop","node","key"),&Tween::stop ); + ObjectTypeDB::bind_method(_MD("stop","object","key"),&Tween::stop ); ObjectTypeDB::bind_method(_MD("stop_all"),&Tween::stop_all ); - ObjectTypeDB::bind_method(_MD("resume","node","key"),&Tween::resume ); + ObjectTypeDB::bind_method(_MD("resume","object","key"),&Tween::resume ); ObjectTypeDB::bind_method(_MD("resume_all"),&Tween::resume_all ); - ObjectTypeDB::bind_method(_MD("remove","node","key"),&Tween::remove ); + ObjectTypeDB::bind_method(_MD("remove","object","key"),&Tween::remove ); ObjectTypeDB::bind_method(_MD("remove_all"),&Tween::remove_all ); ObjectTypeDB::bind_method(_MD("seek","time"),&Tween::seek ); ObjectTypeDB::bind_method(_MD("tell"),&Tween::tell ); ObjectTypeDB::bind_method(_MD("get_runtime"),&Tween::get_runtime ); - ObjectTypeDB::bind_method(_MD("interpolate_property","node","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("interpolate_method","node","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("interpolate_callback","node","callback","times_in_sec","args"),&Tween::interpolate_callback, DEFVAL(Variant()) ); - ObjectTypeDB::bind_method(_MD("follow_property","node","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("follow_method","node","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("targeting_property","node","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) ); - ObjectTypeDB::bind_method(_MD("targeting_method","node","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("interpolate_property","object","property","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_property, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("interpolate_method","object","method","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::interpolate_method, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("interpolate_callback","object","times_in_sec","callback","args"),&Tween::interpolate_callback, DEFVAL(Variant()) ); + ObjectTypeDB::bind_method(_MD("follow_property","object","property","initial_val","target","target_property","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_property, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("follow_method","object","method","initial_val","target","target_method","times_in_sec","trans_type","ease_type","delay"),&Tween::follow_method, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("targeting_property","object","property","initial","initial_val","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_property, DEFVAL(0) ); + ObjectTypeDB::bind_method(_MD("targeting_method","object","method","initial","initial_method","final_val","times_in_sec","trans_type","ease_type","delay"),&Tween::targeting_method, DEFVAL(0) ); - ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) ); - ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) ); - ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"node"), PropertyInfo( Variant::STRING,"key")) ); + ADD_SIGNAL( MethodInfo("tween_start", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) ); + ADD_SIGNAL( MethodInfo("tween_step", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key"), PropertyInfo( Variant::REAL,"elapsed"), PropertyInfo( Variant::OBJECT,"value")) ); + ADD_SIGNAL( MethodInfo("tween_complete", PropertyInfo( Variant::OBJECT,"object"), PropertyInfo( Variant::STRING,"key")) ); ADD_PROPERTY( PropertyInfo( Variant::INT, "playback/process_mode", PROPERTY_HINT_ENUM, "Fixed,Idle"), _SCS("set_tween_process_mode"), _SCS("get_tween_process_mode")); - //ADD_PROPERTY( PropertyInfo( Variant::BOOL, "activate"), _SCS("set_active"), _SCS("is_active")); + + BIND_CONSTANT(TWEEN_PROCESS_FIXED); + BIND_CONSTANT(TWEEN_PROCESS_IDLE); BIND_CONSTANT(TRANS_LINEAR); BIND_CONSTANT(TRANS_SINE); @@ -181,19 +183,19 @@ Variant& Tween::_get_initial_val(InterpolateData& p_data) { case TARGETING_PROPERTY: case TARGETING_METHOD: { - Node *node = get_node(p_data.target); - ERR_FAIL_COND_V(node == NULL,p_data.initial_val); + Object *object = ObjectDB::get_instance(p_data.target_id); + ERR_FAIL_COND_V(object == NULL,p_data.initial_val); static Variant initial_val; if(p_data.type == TARGETING_PROPERTY) { bool valid = false; - initial_val = node->get(p_data.target_key, &valid); + initial_val = object->get(p_data.target_key, &valid); ERR_FAIL_COND_V(!valid,p_data.initial_val); } else { Variant::CallError error; - initial_val = node->call(p_data.target_key, NULL, 0, error); + initial_val = object->call(p_data.target_key, NULL, 0, error); ERR_FAIL_COND_V(error.error != Variant::CallError::CALL_OK,p_data.initial_val); } return initial_val; @@ -213,7 +215,7 @@ Variant& Tween::_get_delta_val(InterpolateData& p_data) { case FOLLOW_PROPERTY: case FOLLOW_METHOD: { - Node *target = get_node(p_data.target); + Object *target = ObjectDB::get_instance(p_data.target_id); ERR_FAIL_COND_V(target == NULL,p_data.initial_val); Variant final_val; @@ -264,6 +266,11 @@ Variant Tween::_run_equation(InterpolateData& p_data) { switch(initial_val.get_type()) { + + case Variant::BOOL: + result = ((int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec)) >= 0.5; + break; + case Variant::INT: result = (int) _run_equation(p_data.trans_type, p_data.ease_type, p_data.elapsed - p_data.delay, (int) initial_val, (int) delta_val, p_data.times_in_sec); break; @@ -409,7 +416,7 @@ Variant Tween::_run_equation(InterpolateData& p_data) { bool Tween::_apply_tween_value(InterpolateData& p_data, Variant& value) { - Object *object = get_node(p_data.path); + Object *object = ObjectDB::get_instance(p_data.id); ERR_FAIL_COND_V(object == NULL, false); switch(p_data.type) { @@ -452,6 +459,7 @@ void Tween::_tween_process(float p_delta) { return; p_delta *= speed_scale; + pending_update ++; // if repeat and all interpolates was finished then reset all interpolates if(repeat) { bool all_finished = true; @@ -476,7 +484,7 @@ void Tween::_tween_process(float p_delta) { if(!data.active || data.finish) continue; - Object *object = get_node(data.path); + Object *object = ObjectDB::get_instance(data.id); if(object == NULL) continue; @@ -523,6 +531,7 @@ void Tween::_tween_process(float p_delta) { if(data.finish) emit_signal("tween_complete",object,data.key); } + pending_update --; } void Tween::set_tween_process_mode(TweenProcessMode p_mode) { @@ -598,16 +607,17 @@ bool Tween::start() { return true; } -bool Tween::reset(Node *p_node, String p_key) { +bool Tween::reset(Object *p_object, String p_key) { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) { + if(object == p_object && data.key == p_key) { data.elapsed = 0; data.finish = false; @@ -615,11 +625,13 @@ bool Tween::reset(Node *p_node, String p_key) { _apply_tween_value(data, data.initial_val); } } + pending_update --; return true; } bool Tween::reset_all() { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); @@ -628,20 +640,23 @@ bool Tween::reset_all() { if(data.delay == 0) _apply_tween_value(data, data.initial_val); } + pending_update --; return true; } -bool Tween::stop(Node *p_node, String p_key) { +bool Tween::stop(Object *p_object, String p_key) { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) + if(object == p_object && data.key == p_key) data.active = false; } + pending_update --; return true; } @@ -650,28 +665,32 @@ bool Tween::stop_all() { set_active(false); _set_process(false); + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); data.active = false; } + pending_update --; return true; } -bool Tween::resume(Node *p_node, String p_key) { +bool Tween::resume(Object *p_object, String p_key) { set_active(true); _set_process(true); + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) + if(object == p_object && data.key == p_key) data.active = true; } + pending_update --; return true; } @@ -680,23 +699,26 @@ bool Tween::resume_all() { set_active(true); _set_process(true); + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); data.active = true; } + pending_update --; return true; } -bool Tween::remove(Node *p_node, String p_key) { +bool Tween::remove(Object *p_object, String p_key) { + ERR_FAIL_COND_V(pending_update != 0, false); for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); - Node *node = get_node(data.path); - if(node == NULL) + Object *object = ObjectDB::get_instance(data.id); + if(object == NULL) continue; - if(node == p_node && data.key == p_key) { + if(object == p_object && data.key == p_key) { interpolates.erase(E); return true; } @@ -706,6 +728,7 @@ bool Tween::remove(Node *p_node, String p_key) { bool Tween::remove_all() { + ERR_FAIL_COND_V(pending_update != 0, false); set_active(false); _set_process(false); interpolates.clear(); @@ -714,6 +737,7 @@ bool Tween::remove_all() { bool Tween::seek(real_t p_time) { + pending_update ++; for(List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { InterpolateData& data = E->get(); @@ -744,11 +768,13 @@ bool Tween::seek(real_t p_time) { _apply_tween_value(data, result); } + pending_update --; return true; } real_t Tween::tell() const { + pending_update ++; real_t pos = 0; for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { @@ -756,11 +782,13 @@ real_t Tween::tell() const { if(data.elapsed > pos) pos = data.elapsed; } + pending_update --; return pos; } real_t Tween::get_runtime() const { + pending_update ++; real_t runtime = 0; for(const List<InterpolateData>::Element *E=interpolates.front();E;E=E->next()) { @@ -769,6 +797,7 @@ real_t Tween::get_runtime() const { if(t > runtime) runtime = t; } + pending_update --; return runtime; } @@ -779,6 +808,12 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final Variant& delta_val = p_delta_val; switch(initial_val.get_type()) { + + case Variant::BOOL: + //delta_val = p_final_val; + delta_val = (int) p_final_val - (int) p_initial_val; + break; + case Variant::INT: delta_val = (int) final_val - (int) initial_val; break; @@ -873,7 +908,7 @@ bool Tween::_calc_delta_val(const Variant& p_initial_val, const Variant& p_final return true; } -bool Tween::interpolate_property(Node *p_node +bool Tween::interpolate_property(Object *p_object , String p_property , Variant p_initial_val , Variant p_final_val @@ -882,11 +917,12 @@ bool Tween::interpolate_property(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); @@ -894,7 +930,7 @@ bool Tween::interpolate_property(Node *p_node ERR_FAIL_COND_V(p_delay < 0, false); bool prop_valid = false; - p_node->get(p_property,&prop_valid); + p_object->get(p_property,&prop_valid); ERR_FAIL_COND_V(!prop_valid, false); InterpolateData data; @@ -903,7 +939,7 @@ bool Tween::interpolate_property(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_property; data.initial_val = p_initial_val; data.final_val = p_final_val; @@ -919,7 +955,7 @@ bool Tween::interpolate_property(Node *p_node return true; } -bool Tween::interpolate_method(Node *p_node +bool Tween::interpolate_method(Object *p_object , String p_method , Variant p_initial_val , Variant p_final_val @@ -928,18 +964,19 @@ bool Tween::interpolate_method(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial_val.get_type() != p_final_val.get_type(), false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); ERR_FAIL_COND_V(p_delay < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_method), false); + ERR_FAIL_COND_V(!p_object->has_method(p_method), false); InterpolateData data; data.active = true; @@ -947,7 +984,7 @@ bool Tween::interpolate_method(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_method; data.initial_val = p_initial_val; data.final_val = p_final_val; @@ -963,16 +1000,17 @@ bool Tween::interpolate_method(Node *p_node return true; } -bool Tween::interpolate_callback(Node *p_node - , String p_callback +bool Tween::interpolate_callback(Object *p_object , real_t p_times_in_sec + , String p_callback , Variant p_arg ) { - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(pending_update != 0, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_times_in_sec < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_callback), false); + ERR_FAIL_COND_V(!p_object->has_method(p_callback), false); InterpolateData data; data.active = true; @@ -980,30 +1018,33 @@ bool Tween::interpolate_callback(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_callback; data.times_in_sec = p_times_in_sec; data.delay = 0; data.arg = p_arg; + pending_update ++; interpolates.push_back(data); + pending_update --; return true; } -bool Tween::follow_property(Node *p_node +bool Tween::follow_property(Object *p_object , String p_property , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_property , real_t p_times_in_sec , TransitionType p_trans_type , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_target == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); @@ -1011,7 +1052,7 @@ bool Tween::follow_property(Node *p_node ERR_FAIL_COND_V(p_delay < 0, false); bool prop_valid = false; - p_node->get(p_property,&prop_valid); + p_object->get(p_property,&prop_valid); ERR_FAIL_COND_V(!prop_valid, false); bool target_prop_valid = false; @@ -1028,10 +1069,10 @@ bool Tween::follow_property(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_property; data.initial_val = p_initial_val; - data.target = p_target->get_path(); + data.target_id = p_target->get_instance_ID(); data.target_key = p_target_property; data.times_in_sec = p_times_in_sec; data.trans_type = p_trans_type; @@ -1042,27 +1083,28 @@ bool Tween::follow_property(Node *p_node return true; } -bool Tween::follow_method(Node *p_node +bool Tween::follow_method(Object *p_object , String p_method , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_method , real_t p_times_in_sec , TransitionType p_trans_type , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_initial_val.get_type() == Variant::INT) p_initial_val = p_initial_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_target == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); ERR_FAIL_COND_V(p_delay < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_method), false); + ERR_FAIL_COND_V(!p_object->has_method(p_method), false); ERR_FAIL_COND_V(!p_target->has_method(p_target_method), false); Variant::CallError error; @@ -1079,10 +1121,10 @@ bool Tween::follow_method(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_method; data.initial_val = p_initial_val; - data.target = p_target->get_path(); + data.target_id = p_target->get_instance_ID(); data.target_key = p_target_method; data.times_in_sec = p_times_in_sec; data.trans_type = p_trans_type; @@ -1093,9 +1135,9 @@ bool Tween::follow_method(Node *p_node return true; } -bool Tween::targeting_property(Node *p_node +bool Tween::targeting_property(Object *p_object , String p_property - , Node *p_initial + , Object *p_initial , String p_initial_property , Variant p_final_val , real_t p_times_in_sec @@ -1103,10 +1145,11 @@ bool Tween::targeting_property(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); @@ -1114,7 +1157,7 @@ bool Tween::targeting_property(Node *p_node ERR_FAIL_COND_V(p_delay < 0, false); bool prop_valid = false; - p_node->get(p_property,&prop_valid); + p_object->get(p_property,&prop_valid); ERR_FAIL_COND_V(!prop_valid, false); bool initial_prop_valid = false; @@ -1131,9 +1174,9 @@ bool Tween::targeting_property(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_property; - data.target = p_initial->get_path(); + data.target_id = p_initial->get_instance_ID(); data.target_key = p_initial_property; data.initial_val = initial_val; data.final_val = p_final_val; @@ -1150,9 +1193,9 @@ bool Tween::targeting_property(Node *p_node } -bool Tween::targeting_method(Node *p_node +bool Tween::targeting_method(Object *p_object , String p_method - , Node *p_initial + , Object *p_initial , String p_initial_method , Variant p_final_val , real_t p_times_in_sec @@ -1160,17 +1203,18 @@ bool Tween::targeting_method(Node *p_node , EaseType p_ease_type , real_t p_delay ) { + ERR_FAIL_COND_V(pending_update != 0, false); // convert INT to REAL is better for interpolaters if(p_final_val.get_type() == Variant::INT) p_final_val = p_final_val.operator real_t(); - ERR_FAIL_COND_V(p_node == NULL, false); + ERR_FAIL_COND_V(p_object == NULL, false); ERR_FAIL_COND_V(p_initial == NULL, false); ERR_FAIL_COND_V(p_times_in_sec <= 0, false); ERR_FAIL_COND_V(p_trans_type < 0 || p_trans_type >= TRANS_COUNT, false); ERR_FAIL_COND_V(p_ease_type < 0 || p_ease_type >= EASE_COUNT, false); ERR_FAIL_COND_V(p_delay < 0, false); - ERR_FAIL_COND_V(!p_node->has_method(p_method), false); + ERR_FAIL_COND_V(!p_object->has_method(p_method), false); ERR_FAIL_COND_V(!p_initial->has_method(p_initial_method), false); Variant::CallError error; @@ -1187,9 +1231,9 @@ bool Tween::targeting_method(Node *p_node data.finish = false; data.elapsed = 0; - data.path = p_node->get_path(); + data.id = p_object->get_instance_ID(); data.key = p_method; - data.target = p_initial->get_path(); + data.target_id = p_initial->get_instance_ID(); data.target_key = p_initial_method; data.initial_val = initial_val; data.final_val = p_final_val; @@ -1213,6 +1257,7 @@ Tween::Tween() { active=false; repeat=false; speed_scale=1; + pending_update=0; } Tween::~Tween() { diff --git a/scene/animation/tween.h b/scene/animation/tween.h index c9d9863397..3e23cc362a 100644 --- a/scene/animation/tween.h +++ b/scene/animation/tween.h @@ -54,15 +54,17 @@ public: TRANS_CIRC, TRANS_BOUNCE, TRANS_BACK, - TRANS_COUNT, + + TRANS_COUNT, }; enum EaseType { EASE_IN, EASE_OUT, EASE_IN_OUT, - EASE_OUT_IN, - EASE_COUNT, + EASE_OUT_IN, + + EASE_COUNT, }; private: @@ -82,12 +84,12 @@ private: InterpolateType type; bool finish; real_t elapsed; - NodePath path; + ObjectID id; StringName key; Variant initial_val; Variant delta_val; Variant final_val; - NodePath target; + ObjectID target_id; StringName target_key; real_t times_in_sec; TransitionType trans_type; @@ -102,6 +104,7 @@ private: bool active; bool repeat; float speed_scale; + mutable int pending_update; List<InterpolateData> interpolates; @@ -142,20 +145,20 @@ public: float get_speed() const; bool start(); - bool reset(Node *p_node, String p_key); + bool reset(Object *p_node, String p_key); bool reset_all(); - bool stop(Node *p_node, String p_key); + bool stop(Object *p_node, String p_key); bool stop_all(); - bool resume(Node *p_node, String p_key); + bool resume(Object *p_node, String p_key); bool resume_all(); - bool remove(Node *p_node, String p_key); + bool remove(Object *p_node, String p_key); bool remove_all(); bool seek(real_t p_time); real_t tell() const; real_t get_runtime() const; - bool interpolate_property(Node *p_node + bool interpolate_property(Object *p_node , String p_property , Variant p_initial_val , Variant p_final_val @@ -165,7 +168,7 @@ public: , real_t p_delay = 0 ); - bool interpolate_method(Node *p_node + bool interpolate_method(Object *p_node , String p_method , Variant p_initial_val , Variant p_final_val @@ -175,16 +178,16 @@ public: , real_t p_delay = 0 ); - bool interpolate_callback(Node *p_node - , String p_callback + bool interpolate_callback(Object *p_node , real_t p_times_in_sec + , String p_callback , Variant p_arg = Variant() ); - bool follow_property(Node *p_node + bool follow_property(Object *p_node , String p_property , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_property , real_t p_times_in_sec , TransitionType p_trans_type @@ -192,10 +195,10 @@ public: , real_t p_delay = 0 ); - bool follow_method(Node *p_node + bool follow_method(Object *p_node , String p_method , Variant p_initial_val - , Node *p_target + , Object *p_target , String p_target_method , real_t p_times_in_sec , TransitionType p_trans_type @@ -203,9 +206,9 @@ public: , real_t p_delay = 0 ); - bool targeting_property(Node *p_node + bool targeting_property(Object *p_node , String p_property - , Node *p_initial + , Object *p_initial , String p_initial_property , Variant p_final_val , real_t p_times_in_sec @@ -214,9 +217,9 @@ public: , real_t p_delay = 0 ); - bool targeting_method(Node *p_node + bool targeting_method(Object *p_node , String p_method - , Node *p_initial + , Object *p_initial , String p_initial_method , Variant p_final_val , real_t p_times_in_sec diff --git a/scene/audio/event_player.cpp b/scene/audio/event_player.cpp index 6bad94bf0e..dc46f4711c 100644 --- a/scene/audio/event_player.cpp +++ b/scene/audio/event_player.cpp @@ -33,13 +33,13 @@ void EventPlayer::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { //set_idle_process(false); //don't annoy - if (playback.is_valid() && autoplay && !get_scene()->is_editor_hint()) + if (playback.is_valid() && autoplay && !get_tree()->is_editor_hint()) play(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { stop(); //wathever it may be doing, stop } break; @@ -75,7 +75,7 @@ Ref<EventStream> EventPlayer::get_stream() const { void EventPlayer::play() { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); if (playback.is_null()) { return; } @@ -93,7 +93,7 @@ void EventPlayer::play() { void EventPlayer::stop() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (playback.is_null()) return; @@ -241,7 +241,7 @@ bool EventPlayer::is_paused() const { void EventPlayer::_set_play(bool p_play) { _play=p_play; - if (is_inside_scene()) { + if (is_inside_tree()) { if(_play) play(); else @@ -280,8 +280,8 @@ float EventPlayer::get_channel_last_note_time(int p_channel) const { void EventPlayer::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&EventPlayer::set_stream); - ObjectTypeDB::bind_method(_MD("get_stream:Stream"),&EventPlayer::get_stream); + ObjectTypeDB::bind_method(_MD("set_stream","stream:EventStream"),&EventPlayer::set_stream); + ObjectTypeDB::bind_method(_MD("get_stream:EventStream"),&EventPlayer::get_stream); ObjectTypeDB::bind_method(_MD("play"),&EventPlayer::play); ObjectTypeDB::bind_method(_MD("stop"),&EventPlayer::stop); diff --git a/scene/audio/sample_player.cpp b/scene/audio/sample_player.cpp index 90994f01b4..bf1c5e97a3 100644 --- a/scene/audio/sample_player.cpp +++ b/scene/audio/sample_player.cpp @@ -498,6 +498,7 @@ bool SamplePlayer::is_active() const { void SamplePlayer::set_sample_library(const Ref<SampleLibrary>& p_library) { library=p_library; + _change_notify(); } Ref<SampleLibrary> SamplePlayer::get_sample_library() const { diff --git a/scene/audio/sound_room_params.cpp b/scene/audio/sound_room_params.cpp index 3e0a64b3f1..f1067f12e0 100644 --- a/scene/audio/sound_room_params.cpp +++ b/scene/audio/sound_room_params.cpp @@ -53,8 +53,8 @@ void SoundRoomParams::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { -#if 0 + case NOTIFICATION_ENTER_TREE: { +//#if 0 Node *n=this; Room *room_instance=NULL; while(n) { @@ -74,14 +74,14 @@ void SoundRoomParams::_notification(int p_what) { if (room_instance) { room=room_instance->get_sound_room(); } else { - room=get_scene()->get_default_world()->get_sound_space(); + room=get_viewport()->find_world()->get_sound_space(); } _update_sound_room(); -#endif +//#endif } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { room=RID(); diff --git a/scene/audio/stream_player.cpp b/scene/audio/stream_player.cpp index 5084c1295b..73025fb52c 100644 --- a/scene/audio/stream_player.cpp +++ b/scene/audio/stream_player.cpp @@ -33,13 +33,13 @@ void StreamPlayer::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { //set_idle_process(false); //don't annoy - if (stream.is_valid() && autoplay && !get_scene()->is_editor_hint()) + if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint()) play(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { stop(); //wathever it may be doing, stop } break; @@ -75,7 +75,7 @@ Ref<AudioStream> StreamPlayer::get_stream() const { void StreamPlayer::play() { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); if (stream.is_null()) return; if (stream->is_playing()) @@ -91,7 +91,7 @@ void StreamPlayer::play() { void StreamPlayer::stop() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (stream.is_null()) return; @@ -214,7 +214,7 @@ bool StreamPlayer::is_paused() const { void StreamPlayer::_set_play(bool p_play) { _play=p_play; - if (is_inside_scene()) { + if (is_inside_tree()) { if(_play) play(); else diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp index ac2417d539..0167687621 100644 --- a/scene/gui/base_button.cpp +++ b/scene/gui/base_button.cpp @@ -30,7 +30,7 @@ #include "os/keyboard.h" #include "print_string.h" #include "button_group.h" - +#include "scene/scene_string_names.h" void BaseButton::_input_event(InputEvent p_event) { @@ -56,13 +56,25 @@ void BaseButton::_input_event(InputEvent p_event) { if (!toggle_mode) { //mouse press attempt + status.press_attempt=true; + status.pressing_inside=true; + pressed(); + if (get_script_instance()) { + Variant::CallError ce; + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed,NULL,0,ce); + } + emit_signal("pressed"); } else { status.pressed=!status.pressed; pressed(); + if (get_script_instance()) { + Variant::CallError ce; + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed,NULL,0,ce); + } emit_signal("pressed"); toggled(status.pressed); @@ -71,8 +83,15 @@ void BaseButton::_input_event(InputEvent p_event) { } - } + } else { + if (status.press_attempt && status.pressing_inside) { +// released(); + emit_signal("released"); + } + status.press_attempt=false; + } + update(); break; } @@ -85,14 +104,19 @@ void BaseButton::_input_event(InputEvent p_event) { if (status.press_attempt &&status.pressing_inside) { - + if (!toggle_mode) { //mouse press attempt - + pressed(); - emit_signal("pressed"); + if (get_script_instance()) { + Variant::CallError ce; + get_script_instance()->call(SceneStringNames::get_singleton()->_pressed,NULL,0,ce); + } + + emit_signal("pressed"); } else { - + status.pressed=!status.pressed; pressed(); @@ -100,11 +124,15 @@ void BaseButton::_input_event(InputEvent p_event) { toggled(status.pressed); emit_signal("toggled",status.pressed); - + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_toggled,status.pressed); + } + + } - + } - + status.press_attempt=false; } @@ -167,6 +195,9 @@ void BaseButton::_input_event(InputEvent p_event) { emit_signal("pressed"); toggled(status.pressed); + if (get_script_instance()) { + get_script_instance()->call(SceneStringNames::get_singleton()->_toggled,status.pressed); + } emit_signal("toggled",status.pressed); } } @@ -201,7 +232,7 @@ void BaseButton::_notification(int p_what) { } } - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { CanvasItem *ci=this; while(ci) { @@ -217,7 +248,7 @@ void BaseButton::_notification(int p_what) { } } - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { if (group) group->_remove_button(this); @@ -336,6 +367,8 @@ bool BaseButton::get_click_on_press() const { } + + void BaseButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&BaseButton::_input_event); @@ -348,13 +381,24 @@ void BaseButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("is_disabled"),&BaseButton::is_disabled); ObjectTypeDB::bind_method(_MD("set_click_on_press","enable"),&BaseButton::set_click_on_press); ObjectTypeDB::bind_method(_MD("get_click_on_press"),&BaseButton::get_click_on_press); + ObjectTypeDB::bind_method(_MD("get_draw_mode"),&BaseButton::get_draw_mode); + + BIND_VMETHOD(MethodInfo("_pressed")); + BIND_VMETHOD(MethodInfo("_toggled",PropertyInfo(Variant::BOOL,"pressed"))); 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_PROPERTY( PropertyInfo( Variant::BOOL, "toggle_mode"), _SCS("set_toggle_mode"), _SCS("is_toggle_mode")); ADD_PROPERTY( PropertyInfo( Variant::BOOL, "click_on_press"), _SCS("set_click_on_press"), _SCS("get_click_on_press")); + + BIND_CONSTANT( DRAW_NORMAL ); + BIND_CONSTANT( DRAW_PRESSED ); + BIND_CONSTANT( DRAW_HOVER ); + BIND_CONSTANT( DRAW_DISABLED ); + } BaseButton::BaseButton() { diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h index a2c640b9cf..a376591ebb 100644 --- a/scene/gui/base_button.h +++ b/scene/gui/base_button.h @@ -61,15 +61,8 @@ class BaseButton : public Control { protected: - enum DrawMode { - DRAW_NORMAL, - DRAW_PRESSED, - DRAW_HOVER, - DRAW_DISABLED, - }; - DrawMode get_draw_mode() const; virtual void pressed(); virtual void toggled(bool p_pressed); @@ -78,7 +71,16 @@ protected: void _notification(int p_what); public: - + + enum DrawMode { + DRAW_NORMAL, + DRAW_PRESSED, + DRAW_HOVER, + DRAW_DISABLED, + }; + + DrawMode get_draw_mode() const; + /* Signals */ bool is_pressed() const; ///< return wether button is pressed (toggled in) @@ -101,4 +103,6 @@ public: }; +VARIANT_ENUM_CAST( BaseButton::DrawMode ); + #endif diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp index 216c6d7122..5ed60e88f8 100644 --- a/scene/gui/box_container.cpp +++ b/scene/gui/box_container.cpp @@ -44,7 +44,7 @@ void BoxContainer::_resort() { Size2i new_size=get_size();; - int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer"); + int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer"); bool first=true; int children_count=0; @@ -202,7 +202,7 @@ Size2 BoxContainer::get_minimum_size() const { /* Calculate MINIMUM SIZE */ Size2i minimum; - int sep=get_constant("separation",vertical?"VBoxContainer":"HBoxContainer"); + int sep=get_constant("separation");//,vertical?"VBoxContainer":"HBoxContainer"); bool first=true; diff --git a/scene/gui/button_group.cpp b/scene/gui/button_group.cpp index 65cfd03505..94cc0a8d51 100644 --- a/scene/gui/button_group.cpp +++ b/scene/gui/button_group.cpp @@ -67,6 +67,9 @@ Array ButtonGroup::_get_button_list() const { List<BaseButton*> b; get_button_list(&b); + + b.sort_custom<Node::Comparator>(); + Array arr; arr.resize(b.size()); @@ -114,7 +117,7 @@ BaseButton *ButtonGroup::get_focused_button() const{ int ButtonGroup::get_pressed_button_index() const { //in tree order, this is bizarre - ERR_FAIL_COND_V(!is_inside_scene(),0); + ERR_FAIL_COND_V(!is_inside_tree(),0); BaseButton *pressed = get_pressed_button(); if (!pressed) diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 6543a0388d..bb61723acf 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -67,7 +67,7 @@ void Container::remove_child_notify(Node *p_child) { void Container::_sort_children() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; notification(NOTIFICATION_SORT_CHILDREN); @@ -101,7 +101,7 @@ void Container::fit_child_in_rect(Control *p_child,const Rect2& p_rect) { void Container::queue_sort() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (pending_sort) @@ -115,7 +115,7 @@ void Container::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { pending_sort=false; queue_sort(); } break; diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index fc24294a70..ce268843b1 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -183,7 +183,7 @@ bool Control::_set(const StringName& p_name, const Variant& p_value) { void Control::_update_minimum_size() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; data.pending_min_size_update=false; @@ -341,7 +341,7 @@ void Control::_notification(int p_notification) { switch(p_notification) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (data.window==this) { @@ -365,7 +365,7 @@ void Control::_notification(int p_notification) { window->drag_attempted=false; window->drag_preview=NULL; - if (get_scene()->is_editor_hint()) { + if (get_tree()->is_editor_hint()) { Node *n = this; while(n) { @@ -385,7 +385,7 @@ void Control::_notification(int p_notification) { _size_changed(); } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { if (data.window) { @@ -630,7 +630,7 @@ void Control::_notification(int p_notification) { } } break; - case SceneMainLoop::NOTIFICATION_WM_UNFOCUS_REQUEST: { + case SceneTree::NOTIFICATION_WM_UNFOCUS_REQUEST: { if (!window) return; @@ -710,7 +710,7 @@ void Control::drop_data(const Point2& p_point,const Variant& p_data){ void Control::force_drag(const Variant& p_data,Control *p_control) { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND(!data.window); ERR_FAIL_COND(p_data.get_type()==Variant::NIL); @@ -728,8 +728,8 @@ void Control::set_drag_preview(Control *p_control) { ERR_FAIL_NULL(p_control); ERR_FAIL_COND( !((Object*)p_control)->cast_to<Control>()); - ERR_FAIL_COND(!is_inside_scene() || !data.window); - ERR_FAIL_COND(p_control->is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree() || !data.window); + ERR_FAIL_COND(p_control->is_inside_tree()); ERR_FAIL_COND(p_control->get_parent()!=NULL); if (data.window->window->drag_preview) { @@ -963,8 +963,8 @@ void Control::_window_input_event(InputEvent p_event) { if (top->data.modal_exclusive) { //cancel event, sorry, modal exclusive EATS UP ALL - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); - get_scene()->set_input_as_handled(); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->set_input_as_handled(); return; // no one gets the event if exclusive NO ONE } @@ -1034,8 +1034,8 @@ void Control::_window_input_event(InputEvent p_event) { _window_call_input(window->mouse_focus,p_event); } - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); - get_scene()->set_input_as_handled(); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->set_input_as_handled(); } else { @@ -1079,8 +1079,8 @@ void Control::_window_input_event(InputEvent p_event) { } - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); - get_scene()->set_input_as_handled(); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->set_input_as_handled(); } } break; @@ -1126,6 +1126,7 @@ void Control::_window_input_event(InputEvent p_event) { over = _find_control_at_pos(this,pos,parent_xform,window->focus_inv_xform); } + if (window->drag_data.get_type()==Variant::NIL && over && !window->modal_stack.empty()) { Control *top = window->modal_stack.back()->get(); @@ -1147,7 +1148,7 @@ void Control::_window_input_event(InputEvent p_event) { window->mouse_over=over; - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_tooltip"); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_tooltip"); if (window->drag_preview) { window->drag_preview->set_pos(pos); @@ -1203,8 +1204,8 @@ void Control::_window_input_event(InputEvent p_event) { - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); - get_scene()->set_input_as_handled(); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->set_input_as_handled(); if (window->drag_data.get_type()!=Variant::NIL && p_event.mouse_motion.button_mask&BUTTON_MASK_LEFT) { @@ -1230,7 +1231,7 @@ void Control::_window_input_event(InputEvent p_event) { if (window->key_event_accepted) { - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); break; } } @@ -1290,7 +1291,7 @@ void Control::_window_input_event(InputEvent p_event) { if (next) { next->grab_focus(); - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_cancel_input_ID",p_event.ID); } } @@ -1305,7 +1306,7 @@ Control *Control::get_window() const { bool Control::is_window() const { - return (is_inside_scene() && window); + return (is_inside_tree() && window); } @@ -1325,9 +1326,12 @@ Size2 Control::get_minimum_size() const { Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type) const { - const Ref<Texture>* tex = data.icon_override.getptr(p_name); - if (tex) - return *tex; + if (p_type==StringName()) { + + const Ref<Texture>* tex = data.icon_override.getptr(p_name); + if (tex) + return *tex; + } StringName type = p_type?p_type:get_type_name(); @@ -1353,12 +1357,11 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const { - - const Ref<StyleBox>* style = data.style_override.getptr(p_name); - - - if (style) - return *style; + if (p_type==StringName()) { + const Ref<StyleBox>* style = data.style_override.getptr(p_name); + if (style) + return *style; + } StringName type = p_type?p_type:get_type_name(); @@ -1381,10 +1384,12 @@ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p } Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) const { - - const Ref<Font>* font = data.font_override.getptr(p_name); - if (font) - return *font; + + if (p_type==StringName()) { + const Ref<Font>* font = data.font_override.getptr(p_name); + if (font) + return *font; + } StringName type = p_type?p_type:get_type_name(); @@ -1410,10 +1415,12 @@ Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) c } Color Control::get_color(const StringName& p_name,const StringName& p_type) const { - - const Color* color = data.color_override.getptr(p_name); - if (color) - return *color; + + if (p_type==StringName()) { + const Color* color = data.color_override.getptr(p_name); + if (color) + return *color; + } StringName type = p_type?p_type:get_type_name(); // try with custom themes @@ -1437,10 +1444,12 @@ Color Control::get_color(const StringName& p_name,const StringName& p_type) cons } int Control::get_constant(const StringName& p_name,const StringName& p_type) const { - - const int* constant = data.constant_override.getptr(p_name); - if (constant) - return *constant; + + if (p_type==StringName()) { + const int* constant = data.constant_override.getptr(p_name); + if (constant) + return *constant; + } StringName type = p_type?p_type:get_type_name(); // try with custom themes @@ -1467,9 +1476,11 @@ int Control::get_constant(const StringName& p_name,const StringName& p_type) con bool Control::has_icon(const StringName& p_name,const StringName& p_type) const { - const Ref<Texture>* tex = data.icon_override.getptr(p_name); - if (tex) - return true; + if (p_type==StringName()) { + const Ref<Texture>* tex = data.icon_override.getptr(p_name); + if (tex) + return true; + } StringName type = p_type?p_type:get_type_name(); @@ -1494,11 +1505,12 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const } bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const { - - const Ref<StyleBox>* style = data.style_override.getptr(p_name); - - if (style) - return true; + if (p_type==StringName()) { + const Ref<StyleBox>* style = data.style_override.getptr(p_name); + + if (style) + return true; + } StringName type = p_type?p_type:get_type_name(); @@ -1523,9 +1535,11 @@ bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) co } bool Control::has_font(const StringName& p_name,const StringName& p_type) const { - const Ref<Font>* font = data.font_override.getptr(p_name); - if (font) - return true; + if (p_type==StringName()) { + const Ref<Font>* font = data.font_override.getptr(p_name); + if (font) + return true; + } StringName type = p_type?p_type:get_type_name(); @@ -1551,9 +1565,11 @@ bool Control::has_font(const StringName& p_name,const StringName& p_type) const } bool Control::has_color(const StringName& p_name,const StringName& p_type) const { - const Color* color = data.color_override.getptr(p_name); - if (color) - return true; + if (p_type==StringName()) { + const Color* color = data.color_override.getptr(p_name); + if (color) + return true; + } StringName type = p_type?p_type:get_type_name(); @@ -1578,10 +1594,13 @@ bool Control::has_color(const StringName& p_name,const StringName& p_type) const } bool Control::has_constant(const StringName& p_name,const StringName& p_type) const { - - const int* constant = data.constant_override.getptr(p_name); - if (constant) - return true; + + if (p_type==StringName()) { + + const int* constant = data.constant_override.getptr(p_name); + if (constant) + return true; + } StringName type = p_type?p_type:get_type_name(); @@ -1607,7 +1626,7 @@ bool Control::has_constant(const StringName& p_name,const StringName& p_type) co Size2 Control::get_parent_area_size() const { - ERR_FAIL_COND_V(!is_inside_scene(),Size2()); + ERR_FAIL_COND_V(!is_inside_tree(),Size2()); Size2 parent_size; @@ -1624,7 +1643,7 @@ Size2 Control::get_parent_area_size() const { void Control::_size_changed() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; Size2 parent_size = get_parent_area_size(); @@ -1677,7 +1696,7 @@ void Control::_size_changed() { float Control::_get_parent_range(int p_idx) const { - if (!is_inside_scene()) { + if (!is_inside_tree()) { return 1.0; @@ -1748,7 +1767,7 @@ float Control::_a2s(float p_val, AnchorType p_anchor,float p_range) const { void Control::set_anchor(Margin p_margin,AnchorType p_anchor) { - if (!is_inside_scene()) { + if (!is_inside_tree()) { data.anchor[p_margin]=p_anchor; } else { @@ -1980,7 +1999,7 @@ void Control::add_constant_override(const StringName& p_name, int p_constant) { void Control::set_focus_mode(FocusMode p_focus_mode) { - if (is_inside_scene() && p_focus_mode == FOCUS_NONE && data.focus_mode!=FOCUS_NONE && has_focus()) + if (is_inside_tree() && p_focus_mode == FOCUS_NONE && data.focus_mode!=FOCUS_NONE && has_focus()) release_focus(); data.focus_mode=p_focus_mode; @@ -2178,7 +2197,7 @@ bool Control::has_focus() const { void Control::grab_focus() { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND(!data.window); if (data.focus_mode==FOCUS_NONE) @@ -2188,7 +2207,7 @@ void Control::grab_focus() { if (data.window->window->key_focus && data.window->window->key_focus==this) return; - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_window_remove_focus"); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_window_remove_focus"); data.window->window->key_focus=this; notification(NOTIFICATION_FOCUS_ENTER); #ifdef DEBUG_ENABLED @@ -2202,13 +2221,13 @@ void Control::grab_focus() { void Control::release_focus() { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND(!data.window); if (!has_focus()) return; - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,"windows","_window_remove_focus"); + get_tree()->call_group(SceneTree::GROUP_CALL_REALTIME,"windows","_window_remove_focus"); //data.window->window->key_focus=this; //notification(NOTIFICATION_FOCUS_ENTER); update(); @@ -2217,12 +2236,12 @@ void Control::release_focus() { bool Control::is_toplevel_control() const { - return is_inside_scene() && (!data.parent_canvas_item && !window && is_set_as_toplevel()); + return is_inside_tree() && (!data.parent_canvas_item && !window && is_set_as_toplevel()); } void Control::show_modal(bool p_exclusive) { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND(!data.SI && data.window!=this); ERR_FAIL_COND(!data.window); @@ -2249,6 +2268,7 @@ void Control::_window_sort_subwindows() { return; window->modal_stack.sort_custom<CComparator>(); + window->subwindows.sort_custom<CComparator>(); window->subwindow_order_dirty=false; } @@ -2282,7 +2302,7 @@ void Control::_modal_stack_remove() { if (!pfoc) return; - if (!pfoc->is_inside_scene() || !pfoc->is_visible()) + if (!pfoc->is_inside_tree() || !pfoc->is_visible()) return; pfoc->grab_focus(); } else { @@ -2332,13 +2352,13 @@ void Control::set_theme(const Ref<Theme>& p_theme) { void Control::_window_accept_event() { window->key_event_accepted=true; - if (is_inside_scene()) - get_scene()->set_input_as_handled(); + if (is_inside_tree()) + get_tree()->set_input_as_handled(); } void Control::accept_event() { - if (is_inside_scene() && get_window()) + if (is_inside_tree() && get_window()) get_window()->_window_accept_event(); } @@ -2585,7 +2605,7 @@ float Control::get_stretch_ratio() const { void Control::grab_click_focus() { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); if (data.window && data.window->window->mouse_focus) { @@ -2620,7 +2640,7 @@ void Control::grab_click_focus() { void Control::minimum_size_changed() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (data.pending_min_size_update) @@ -2663,9 +2683,9 @@ bool Control::is_stopping_mouse() const { Control *Control::get_focus_owner() const { - ERR_FAIL_COND_V(!is_inside_scene(),NULL); - ERR_FAIL_COND_V(!window,NULL); - return window->key_focus; + ERR_FAIL_COND_V(!is_inside_tree(),NULL); + ERR_FAIL_COND_V(!data.window,NULL); + return data.window->window->key_focus; } void Control::_bind_methods() { diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index ac0ded03ab..a82cfc7ea6 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -93,7 +93,7 @@ void WindowDialog::_notification(int p_what) { } break; case NOTIFICATION_THEME_CHANGED: - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { close_button->set_normal_texture( get_icon("close","WindowDialog")); close_button->set_pressed_texture( get_icon("close","WindowDialog")); @@ -297,7 +297,7 @@ void AcceptDialog::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_label"),&AcceptDialog::get_label); ObjectTypeDB::bind_method(_MD("set_hide_on_ok","enabled"),&AcceptDialog::set_hide_on_ok); ObjectTypeDB::bind_method(_MD("get_hide_on_ok"),&AcceptDialog::get_hide_on_ok); - ObjectTypeDB::bind_method(_MD("add_button:Button","text","right","action"),&AcceptDialog::add_cancel,DEFVAL(false),DEFVAL("")); + ObjectTypeDB::bind_method(_MD("add_button:Button","text","right","action"),&AcceptDialog::add_button,DEFVAL(false),DEFVAL("")); ObjectTypeDB::bind_method(_MD("add_cancel:Button","name"),&AcceptDialog::add_cancel); ObjectTypeDB::bind_method(_MD("_builtin_text_entered"),&AcceptDialog::_builtin_text_entered); ObjectTypeDB::bind_method(_MD("register_text_enter:LineEdit","line_edit"),&AcceptDialog::register_text_enter); diff --git a/scene/gui/empty_control.cpp b/scene/gui/empty_control.cpp deleted file mode 100644 index 1e377b2b73..0000000000 --- a/scene/gui/empty_control.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************/ -/* empty_control.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "empty_control.h"
-
-Size2 EmptyControl::get_minimum_size() const {
-
- return minsize;
-}
-
-void EmptyControl::set_minsize(const Size2& p_size) {
-
- minsize=p_size;
- minimum_size_changed();
-}
-
-Size2 EmptyControl::get_minsize() const {
-
- return minsize;
-}
-
-
-void EmptyControl::_bind_methods() {
-
-
- ObjectTypeDB::bind_method(_MD("set_minsize","minsize"),&EmptyControl::set_minsize);
- ObjectTypeDB::bind_method(_MD("get_minsize"),&EmptyControl::get_minsize);
-
- ADD_PROPERTY( PropertyInfo(Variant::VECTOR2,"minsize"), _SCS("set_minsize"),_SCS("get_minsize") );
-}
-
-EmptyControl::EmptyControl()
-{
-}
diff --git a/scene/gui/empty_control.h b/scene/gui/empty_control.h deleted file mode 100644 index 993af45ac4..0000000000 --- a/scene/gui/empty_control.h +++ /dev/null @@ -1,48 +0,0 @@ -/*************************************************************************/ -/* empty_control.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef EMPTY_CONTROL_H
-#define EMPTY_CONTROL_H
-
-#include "scene/gui/control.h"
-
-class EmptyControl : public Control {
-
- OBJ_TYPE(EmptyControl,Control);
- Size2 minsize;
-protected:
- static void _bind_methods();
-public:
- virtual Size2 get_minimum_size() const;
- void set_minsize(const Size2& p_size);
- Size2 get_minsize() const;
-
- EmptyControl();
-};
-
-#endif // EMPTY_CONTROL_H
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp new file mode 100644 index 0000000000..3cd0dd3d16 --- /dev/null +++ b/scene/gui/graph_edit.cpp @@ -0,0 +1,586 @@ +#include "graph_edit.h" +#include "os/input.h" +#include "os/keyboard.h" +bool GraphEditFilter::has_point(const Point2& p_point) const { + + return ge->_filter_input(p_point); +} + + +GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) { + + ge=p_edit; +} + + +Error GraphEdit::connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) { + + if (is_node_connected(p_from,p_from_port,p_to,p_to_port)) + return OK; + Connection c; + c.from=p_from; + c.from_port=p_from_port; + c.to=p_to; + c.to_port=p_to_port; + connections.push_back(c); + top_layer->update(); + + return OK; +} + +bool GraphEdit::is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port) { + + for(List<Connection>::Element *E=connections.front();E;E=E->next()) { + + if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) + return true; + } + + return false; + +} + +void GraphEdit::disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port){ + + + for(List<Connection>::Element *E=connections.front();E;E=E->next()) { + + if (E->get().from==p_from && E->get().from_port==p_from_port && E->get().to==p_to && E->get().to_port==p_to_port) { + + connections.erase(E); + top_layer->update(); + return; + } + } +} + +void GraphEdit::get_connection_list(List<Connection> *r_connections) const { + + *r_connections=connections; +} + + +void GraphEdit::_scroll_moved(double) { + + + _update_scroll_offset(); + top_layer->update(); +} + +void GraphEdit::_update_scroll_offset() { + + for(int i=0;i<get_child_count();i++) { + + GraphNode *gn=get_child(i)->cast_to<GraphNode>(); + if (!gn) + continue; + + Point2 pos=gn->get_offset(); + pos-=Point2(h_scroll->get_val(),v_scroll->get_val()); + gn->set_pos(pos); + } + +} + +void GraphEdit::_update_scroll() { + + if (updating) + return; + + updating=true; + Rect2 screen; + for(int i=0;i<get_child_count();i++) { + + GraphNode *gn=get_child(i)->cast_to<GraphNode>(); + if (!gn) + continue; + + Rect2 r; + r.pos=gn->get_offset(); + r.size=gn->get_size(); + screen = screen.merge(r); + } + + screen.pos-=get_size(); + screen.size+=get_size()*2.0; + + + h_scroll->set_min(screen.pos.x); + h_scroll->set_max(screen.pos.x+screen.size.x); + h_scroll->set_page(get_size().x); + if (h_scroll->get_max() - h_scroll->get_min() <= h_scroll->get_page()) + h_scroll->hide(); + else + h_scroll->show(); + + v_scroll->set_min(screen.pos.y); + v_scroll->set_max(screen.pos.y+screen.size.y); + v_scroll->set_page(get_size().y); + + if (v_scroll->get_max() - v_scroll->get_min() <= v_scroll->get_page()) + v_scroll->hide(); + else + v_scroll->show(); + + _update_scroll_offset(); + updating=false; +} + + +void GraphEdit::_graph_node_raised(Node* p_gn) { + + GraphNode *gn=p_gn->cast_to<GraphNode>(); + ERR_FAIL_COND(!gn); + gn->raise(); + top_layer->raise(); + +} + + +void GraphEdit::_graph_node_moved(Node *p_gn) { + + GraphNode *gn=p_gn->cast_to<GraphNode>(); + ERR_FAIL_COND(!gn); + + //gn->set_pos(gn->get_offset()+scroll_offset); + + top_layer->update(); +} + +void GraphEdit::add_child_notify(Node *p_child) { + + top_layer->call_deferred("raise"); //top layer always on top! + GraphNode *gn = p_child->cast_to<GraphNode>(); + if (gn) { + gn->connect("offset_changed",this,"_graph_node_moved",varray(gn)); + gn->connect("raise_request",this,"_graph_node_raised",varray(gn)); + _graph_node_moved(gn); + gn->set_stop_mouse(false); + } +} + +void GraphEdit::remove_child_notify(Node *p_child) { + + top_layer->call_deferred("raise"); //top layer always on top! + GraphNode *gn = p_child->cast_to<GraphNode>(); + if (gn) { + gn->disconnect("offset_changed",this,"_graph_node_moved"); + gn->disconnect("raise_request",this,"_graph_node_raised"); + } +} + +void GraphEdit::_notification(int p_what) { + + if (p_what==NOTIFICATION_READY) { + Size2 size = top_layer->get_size(); + Size2 hmin = h_scroll->get_combined_minimum_size(); + Size2 vmin = v_scroll->get_combined_minimum_size(); + + v_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,vmin.width); + v_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + v_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_BEGIN,0); + v_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + h_scroll->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,0); + h_scroll->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,0); + h_scroll->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,hmin.height); + h_scroll->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,0); + + } + if (p_what==NOTIFICATION_DRAW) { + VS::get_singleton()->canvas_item_set_clip(get_canvas_item(),true); + + } + + if (p_what==NOTIFICATION_RESIZED) { + _update_scroll(); + top_layer->update(); + } +} + +bool GraphEdit::_filter_input(const Point2& p_point) { + + Ref<Texture> port =get_icon("port","GraphNode"); + + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to<GraphNode>(); + if (!gn) + continue; + + for(int j=0;j<gn->get_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + if (pos.distance_to(p_point)<grab_r) + return true; + + + } + + for(int j=0;j<gn->get_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + if (pos.distance_to(p_point)<grab_r) + return true; + + + } + + } + + return false; +} + +void GraphEdit::_top_layer_input(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && p_ev.mouse_button.pressed) { + + Ref<Texture> port =get_icon("port","GraphNode"); + Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y); + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to<GraphNode>(); + if (!gn) + continue; + + for(int j=0;j<gn->get_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + if (pos.distance_to(mpos)<grab_r) { + + connecting=true; + connecting_from=gn->get_name(); + connecting_index=j; + connecting_out=true; + connecting_type=gn->get_connection_output_type(j); + connecting_color=gn->get_connection_output_color(j); + connecting_target=false; + connecting_to=pos; + return; + } + + + } + + for(int j=0;j<gn->get_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + + if (pos.distance_to(mpos)<grab_r) { + + if (right_disconnects) { + //check disconnect + for (List<Connection>::Element*E=connections.front();E;E=E->next()) { + + if (E->get().to==gn->get_name() && E->get().to_port==j) { + + Node*fr = get_node(String(E->get().from)); + if (fr && fr->cast_to<GraphNode>()) { + + connecting_from=E->get().from; + connecting_index=E->get().from_port; + connecting_out=true; + connecting_type=fr->cast_to<GraphNode>()->get_connection_output_type(E->get().from_port); + connecting_color=fr->cast_to<GraphNode>()->get_connection_output_color(E->get().from_port); + connecting_target=false; + connecting_to=pos; + + emit_signal("disconnection_request",E->get().from,E->get().from_port,E->get().to,E->get().to_port); + fr = get_node(String(connecting_from)); //maybe it was erased + if (fr && fr->cast_to<GraphNode>()) { + connecting=true; + } + return; + } + + } + } + } + + + connecting=true; + connecting_from=gn->get_name(); + connecting_index=j; + connecting_out=false; + connecting_type=gn->get_connection_input_type(j); + connecting_color=gn->get_connection_input_color(j); + connecting_target=false; + connecting_to=pos; + return; + } + + + } + } + } + + if (p_ev.type==InputEvent::MOUSE_MOTION && connecting) { + + connecting_to=Vector2(p_ev.mouse_motion.x,p_ev.mouse_motion.y); + connecting_target=false; + top_layer->update(); + + Ref<Texture> port =get_icon("port","GraphNode"); + Vector2 mpos(p_ev.mouse_button.x,p_ev.mouse_button.y); + float grab_r=port->get_width()*0.5; + for(int i=get_child_count()-1;i>=0;i--) { + + GraphNode *gn=get_child(i)->cast_to<GraphNode>(); + if (!gn) + continue; + + if (!connecting_out) { + for(int j=0;j<gn->get_connection_output_count();j++) { + + Vector2 pos = gn->get_connection_output_pos(j)+gn->get_pos(); + int type =gn->get_connection_output_type(j); + if (type==connecting_type && pos.distance_to(mpos)<grab_r) { + + connecting_target=true; + connecting_to=pos; + connecting_target_to=gn->get_name(); + connecting_target_index=j; + return; + } + + + } + } else { + + for(int j=0;j<gn->get_connection_input_count();j++) { + + Vector2 pos = gn->get_connection_input_pos(j)+gn->get_pos(); + int type =gn->get_connection_input_type(j); + if (type==connecting_type && pos.distance_to(mpos)<grab_r) { + connecting_target=true; + connecting_to=pos; + connecting_target_to=gn->get_name(); + connecting_target_index=j; + return; + } + } + } + } + } + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.button_index==BUTTON_LEFT && !p_ev.mouse_button.pressed) { + + if (connecting && connecting_target) { + + String from = connecting_from; + int from_slot = connecting_index; + String to =connecting_target_to; + int to_slot = connecting_target_index; + + if (!connecting_out) { + SWAP(from,to); + SWAP(from_slot,to_slot); + } + emit_signal("connection_request",from,from_slot,to,to_slot); + + } + connecting=false; + top_layer->update(); + + } + + + +} + +void GraphEdit::_draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color) { + + static const int steps = 20; + + Rect2 r; + r.pos=p_from; + r.expand_to(p_to); + Vector2 sign=Vector2((p_from.x < p_to.x) ? 1 : -1,(p_from.y < p_to.y) ? 1 : -1); + bool flip = sign.x * sign.y < 0; + + Vector2 prev; + for(int i=0;i<=steps;i++) { + + float d = i/float(steps); + float c=-Math::cos(d*Math_PI) * 0.5+0.5; + if (flip) + c=1.0-c; + Vector2 p = r.pos+Vector2(d*r.size.width,c*r.size.height); + + if (i>0) { + + top_layer->draw_line(prev,p,p_color,2); + } + + prev=p; + } +} + +void GraphEdit::_top_layer_draw() { + + _update_scroll(); + + if (connecting) { + + Node *fromn = get_node(connecting_from); + ERR_FAIL_COND(!fromn); + GraphNode *from = fromn->cast_to<GraphNode>(); + ERR_FAIL_COND(!from); + Vector2 pos; + if (connecting_out) + pos=from->get_connection_output_pos(connecting_index); + else + pos=from->get_connection_input_pos(connecting_index); + pos+=from->get_pos(); + + Vector2 topos; + topos=connecting_to; + + Color col=connecting_color; + + if (connecting_target) { + col.r+=0.4; + col.g+=0.4; + col.b+=0.4; + } + _draw_cos_line(pos,topos,col); + } + + List<List<Connection>::Element* > to_erase; + for(List<Connection>::Element *E=connections.front();E;E=E->next()) { + + NodePath fromnp(E->get().from); + + Node * from = get_node(fromnp); + if (!from) { + to_erase.push_back(E); + continue; + } + + GraphNode *gfrom = from->cast_to<GraphNode>(); + + if (!gfrom) { + to_erase.push_back(E); + continue; + } + + NodePath tonp(E->get().to); + Node * to = get_node(tonp); + if (!to) { + to_erase.push_back(E); + continue; + } + + GraphNode *gto = to->cast_to<GraphNode>(); + + if (!gto) { + to_erase.push_back(E); + continue; + } + + Vector2 frompos=gfrom->get_connection_output_pos(E->get().from_port)+gfrom->get_pos(); + Color color = gfrom->get_connection_output_color(E->get().from_port); + Vector2 topos=gto->get_connection_input_pos(E->get().to_port)+gto->get_pos(); + _draw_cos_line(frompos,topos,color); + + } + + while(to_erase.size()) { + connections.erase(to_erase.front()->get()); + to_erase.pop_front(); + } + //draw connections +} + +void GraphEdit::_input_event(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_MOTION && (p_ev.mouse_motion.button_mask&BUTTON_MASK_MIDDLE || (p_ev.mouse_motion.button_mask&BUTTON_MASK_LEFT && Input::get_singleton()->is_key_pressed(KEY_SPACE)))) { + h_scroll->set_val( h_scroll->get_val() - p_ev.mouse_motion.relative_x ); + v_scroll->set_val( v_scroll->get_val() - p_ev.mouse_motion.relative_y ); + } +} + +void GraphEdit::clear_connections() { + + connections.clear(); + update(); +} + + +void GraphEdit::set_right_disconnects(bool p_enable) { + + right_disconnects=p_enable; +} + +bool GraphEdit::is_right_disconnects_enabled() const{ + + return right_disconnects; +} + +Array GraphEdit::_get_connection_list() const { + + List<Connection> conns; + get_connection_list(&conns); + Array arr; + for(List<Connection>::Element *E=conns.front();E;E=E->next()) { + Dictionary d; + d["from"]=E->get().from; + d["from_port"]=E->get().from_port; + d["to"]=E->get().to; + d["to_port"]=E->get().to_port; + arr.push_back(d); + } + return arr; +} +void GraphEdit::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("connect_node:Error","from","from_port","to","to_port"),&GraphEdit::connect_node); + ObjectTypeDB::bind_method(_MD("is_node_connected","from","from_port","to","to_port"),&GraphEdit::is_node_connected); + ObjectTypeDB::bind_method(_MD("disconnect_node","from","from_port","to","to_port"),&GraphEdit::disconnect_node); + ObjectTypeDB::bind_method(_MD("get_connection_list"),&GraphEdit::_get_connection_list); + + ObjectTypeDB::bind_method(_MD("set_right_disconnects","enable"),&GraphEdit::set_right_disconnects); + ObjectTypeDB::bind_method(_MD("is_right_disconnects_enabled"),&GraphEdit::is_right_disconnects_enabled); + + ObjectTypeDB::bind_method(_MD("_graph_node_moved"),&GraphEdit::_graph_node_moved); + ObjectTypeDB::bind_method(_MD("_graph_node_raised"),&GraphEdit::_graph_node_raised); + + ObjectTypeDB::bind_method(_MD("_top_layer_input"),&GraphEdit::_top_layer_input); + ObjectTypeDB::bind_method(_MD("_top_layer_draw"),&GraphEdit::_top_layer_draw); + ObjectTypeDB::bind_method(_MD("_scroll_moved"),&GraphEdit::_scroll_moved); + + ObjectTypeDB::bind_method(_MD("_input_event"),&GraphEdit::_input_event); + + ADD_SIGNAL(MethodInfo("connection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot"))); + ADD_SIGNAL(MethodInfo("disconnection_request",PropertyInfo(Variant::STRING,"from"),PropertyInfo(Variant::INT,"from_slot"),PropertyInfo(Variant::STRING,"to"),PropertyInfo(Variant::INT,"to_slot"))); + +} + + + +GraphEdit::GraphEdit() { + top_layer=NULL; + top_layer=memnew(GraphEditFilter(this)); + add_child(top_layer); + top_layer->set_stop_mouse(false); + top_layer->set_area_as_parent_rect(); + top_layer->connect("draw",this,"_top_layer_draw"); + top_layer->set_stop_mouse(false); + top_layer->connect("input_event",this,"_top_layer_input"); + + h_scroll = memnew(HScrollBar); + h_scroll->set_name("_h_scroll"); + top_layer->add_child(h_scroll); + + v_scroll = memnew(VScrollBar); + v_scroll->set_name("_v_scroll"); + top_layer->add_child(v_scroll); + updating=false; + connecting=false; + right_disconnects=false; + + h_scroll->connect("value_changed", this,"_scroll_moved"); + v_scroll->connect("value_changed", this,"_scroll_moved"); +} diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h new file mode 100644 index 0000000000..0a9da73ab6 --- /dev/null +++ b/scene/gui/graph_edit.h @@ -0,0 +1,100 @@ +#ifndef GRAPH_EDIT_H +#define GRAPH_EDIT_H + +#include "scene/gui/graph_node.h" +#include "scene/gui/scroll_bar.h" + +class GraphEdit; + +class GraphEditFilter : public Control { + + OBJ_TYPE(GraphEditFilter,Control); + +friend class GraphEdit; + GraphEdit *ge; + virtual bool has_point(const Point2& p_point) const; + +public: + + + GraphEditFilter(GraphEdit *p_edit); +}; + +class GraphEdit : public Control { + + OBJ_TYPE(GraphEdit,Control); +public: + + struct Connection { + StringName from; + StringName to; + int from_port; + int to_port; + + }; +private: + + HScrollBar* h_scroll; + VScrollBar* v_scroll; + + + bool connecting; + String connecting_from; + bool connecting_out; + int connecting_index; + int connecting_type; + Color connecting_color; + bool connecting_target; + Vector2 connecting_to; + String connecting_target_to; + int connecting_target_index; + + + + bool right_disconnects; + bool updating; + List<Connection> connections; + + void _draw_cos_line(const Vector2& p_from, const Vector2& p_to,const Color& p_color); + + void _graph_node_raised(Node* p_gn); + void _graph_node_moved(Node *p_gn); + + void _update_scroll(); + void _scroll_moved(double); + void _input_event(const InputEvent& p_ev); + + GraphEditFilter *top_layer; + void _top_layer_input(const InputEvent& p_ev); + void _top_layer_draw(); + void _update_scroll_offset(); + + Array _get_connection_list() const; + +friend class GraphEditFilter; + bool _filter_input(const Point2& p_point); +protected: + + static void _bind_methods(); + virtual void add_child_notify(Node *p_child); + virtual void remove_child_notify(Node *p_child); + void _notification(int p_what); + +public: + + Error connect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + bool is_node_connected(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + void disconnect_node(const StringName& p_from, int p_from_port,const StringName& p_to,int p_to_port); + void clear_connections(); + + GraphEditFilter *get_top_layer() const { return top_layer; } + void get_connection_list(List<Connection> *r_connections) const; + + void set_right_disconnects(bool p_enable); + bool is_right_disconnects_enabled() const; + + + GraphEdit(); +}; + +#endif // GRAPHEdit_H diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp new file mode 100644 index 0000000000..444b37855f --- /dev/null +++ b/scene/gui/graph_node.cpp @@ -0,0 +1,583 @@ +#include "graph_node.h" +#include "method_bind_ext.inc" + + +bool GraphNode::_set(const StringName& p_name, const Variant& p_value) { + + if (!p_name.operator String().begins_with("slot/")) + return false; + + int idx=p_name.operator String().get_slice("/",1).to_int(); + String what = p_name.operator String().get_slice("/",2); + + + Slot si; + if (slot_info.has(idx)) + si=slot_info[idx]; + + + if (what=="left_enabled") + si.enable_left=p_value; + else if (what=="left_type") + si.type_left=p_value; + else if (what=="left_color") + si.color_left=p_value; + else if (what=="right_enabled") + si.enable_right=p_value; + else if (what=="right_type") + si.type_right=p_value; + else if (what=="right_color") + si.color_right=p_value; + else + return false; + + set_slot(idx,si.enable_left,si.type_left,si.color_left,si.enable_right,si.type_right,si.color_right); + update(); + return true; +} + +bool GraphNode::_get(const StringName& p_name,Variant &r_ret) const{ + + + + if (!p_name.operator String().begins_with("slot/")) { + return false; + } + + int idx=p_name.operator String().get_slice("/",1).to_int(); + String what = p_name.operator String().get_slice("/",2); + + + + Slot si; + if (slot_info.has(idx)) + si=slot_info[idx]; + + if (what=="left_enabled") + r_ret=si.enable_left; + else if (what=="left_type") + r_ret=si.type_left; + else if (what=="left_color") + r_ret=si.color_left; + else if (what=="right_enabled") + r_ret=si.enable_right; + else if (what=="right_type") + r_ret=si.type_right; + else if (what=="right_color") + r_ret=si.color_right; + else + return false; + + return true; +} +void GraphNode::_get_property_list( List<PropertyInfo> *p_list) const{ + + int idx=0; + for(int i=0;i<get_child_count();i++) { + Control *c=get_child(i)->cast_to<Control>(); + if (!c || c->is_set_as_toplevel() ) + continue; + + String base="slot/"+itos(idx)+"/"; + + p_list->push_back(PropertyInfo(Variant::BOOL,base+"left_enabled")); + p_list->push_back(PropertyInfo(Variant::INT,base+"left_type")); + p_list->push_back(PropertyInfo(Variant::COLOR,base+"left_color")); + p_list->push_back(PropertyInfo(Variant::BOOL,base+"right_enabled")); + p_list->push_back(PropertyInfo(Variant::INT,base+"right_type")); + p_list->push_back(PropertyInfo(Variant::COLOR,base+"right_color")); + + idx++; + } +} + + +void GraphNode::_resort() { + + + + int sep=get_constant("separation"); + Ref<StyleBox> sb=get_stylebox("frame"); + bool first=true; + + Size2 minsize; + + 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; + + Size2i size=c->get_combined_minimum_size(); + + minsize.y+=size.y; + minsize.x=MAX(minsize.x,size.x); + + if (first) + first=false; + else + minsize.y+=sep; + + } + + + int vofs=0; + int w = get_size().x - sb->get_minimum_size().x; + + + cache_y.clear(); + 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; + + Size2i size=c->get_combined_minimum_size(); + + Rect2 r(sb->get_margin(MARGIN_LEFT),sb->get_margin(MARGIN_TOP)+vofs,w,size.y); + + fit_child_in_rect(c,r); + cache_y.push_back(vofs+size.y*0.5); + + if (vofs>0) + vofs+=sep; + vofs+=size.y; + + + } + + _change_notify(); + update(); + connpos_dirty=true; + + +} + + +void GraphNode::_notification(int p_what) { + + if (p_what==NOTIFICATION_DRAW) { + + Ref<StyleBox> sb=get_stylebox("frame"); + Ref<Texture> port =get_icon("port"); + Ref<Texture> close =get_icon("close"); + int close_offset = get_constant("close_offset"); + Ref<Font> title_font = get_font("title_font"); + int title_offset = get_constant("title_offset"); + Color title_color = get_color("title_color"); + Point2i icofs = -port->get_size()*0.5; + int edgeofs=get_constant("port_offset"); + icofs.y+=sb->get_margin(MARGIN_TOP); + draw_style_box(sb,Rect2(Point2(),get_size())); + + int w = get_size().width-sb->get_minimum_size().x; + + if (show_close) + w-=close->get_width(); + + draw_string(title_font,Point2(sb->get_margin(MARGIN_LEFT),-title_font->get_height()+title_font->get_ascent()+title_offset),title,title_color,w); + if (show_close) { + Vector2 cpos = Point2(w+sb->get_margin(MARGIN_LEFT),-close->get_height()+close_offset); + draw_texture(close,cpos); + close_rect.pos=cpos; + close_rect.size=close->get_size(); + } else { + close_rect=Rect2(); + } + + for (Map<int,Slot>::Element *E=slot_info.front();E;E=E->next()) { + + if (E->key() < 0 || E->key()>=cache_y.size()) + continue; + if (!slot_info.has(E->key())) + continue; + const Slot &s=slot_info[E->key()]; + //left + if (s.enable_left) + port->draw(get_canvas_item(),icofs+Point2(edgeofs,cache_y[E->key()]),s.color_left); + if (s.enable_right) + port->draw(get_canvas_item(),icofs+Point2(get_size().x-edgeofs,cache_y[E->key()]),s.color_right); + + } + } + + if (p_what==NOTIFICATION_SORT_CHILDREN) { + + _resort(); + } + +} + + +void GraphNode::set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right) { + + ERR_FAIL_COND(p_idx<0); + + if (!p_enable_left && p_type_left==0 && p_color_left==Color(1,1,1,1) && !p_enable_right && p_type_right==0 && p_color_right==Color(1,1,1,1)) { + slot_info.erase(p_idx); + return; + } + + Slot s; + s.enable_left=p_enable_left; + s.type_left=p_type_left; + s.color_left=p_color_left; + s.enable_right=p_enable_right; + s.type_right=p_type_right; + s.color_right=p_color_right; + slot_info[p_idx]=s; + update(); + connpos_dirty=true; + +} + +void GraphNode::clear_slot(int p_idx){ + + slot_info.erase(p_idx); + update(); + connpos_dirty=true; + +} +void GraphNode::clear_all_slots(){ + + slot_info.clear(); + update(); + connpos_dirty=true; + +} +bool GraphNode::is_slot_enabled_left(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return false; + return slot_info[p_idx].enable_left; + +} + +int GraphNode::get_slot_type_left(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return 0; + return slot_info[p_idx].type_left; + +} + +Color GraphNode::get_slot_color_left(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return Color(1,1,1,1); + return slot_info[p_idx].color_left; + +} + +bool GraphNode::is_slot_enabled_right(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return false; + return slot_info[p_idx].enable_right; + +} + + + +int GraphNode::get_slot_type_right(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return 0; + return slot_info[p_idx].type_right; + +} + +Color GraphNode::get_slot_color_right(int p_idx) const{ + + if (!slot_info.has(p_idx)) + return Color(1,1,1,1); + return slot_info[p_idx].color_right; + +} + +Size2 GraphNode::get_minimum_size() const { + + Ref<Font> title_font = get_font("title_font"); + + int sep=get_constant("separation"); + Ref<StyleBox> sb=get_stylebox("frame"); + bool first=true; + + Size2 minsize; + minsize.x=title_font->get_string_size(title).x; + if (show_close) { + Ref<Texture> close =get_icon("close"); + minsize.x+=sep+close->get_width(); + } + + + 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; + + Size2i size=c->get_combined_minimum_size(); + + minsize.y+=size.y; + minsize.x=MAX(minsize.x,size.x); + + if (first) + first=false; + else + minsize.y+=sep; + } + + return minsize+sb->get_minimum_size(); +} + +void GraphNode::set_title(const String& p_title) { + + title=p_title; + minimum_size_changed(); + update(); + +} + +String GraphNode::get_title() const{ + + return title; +} + +void GraphNode::set_offset(const Vector2& p_offset) { + + offset=p_offset; + emit_signal("offset_changed"); + update(); +} + +Vector2 GraphNode::get_offset() const { + + return offset; +} + + + +void GraphNode::set_show_close_button(bool p_enable){ + + show_close=p_enable; + update(); +} +bool GraphNode::is_close_button_visible() const{ + + return show_close; +} + +void GraphNode::_connpos_update() { + + + int edgeofs=get_constant("port_offset"); + int sep=get_constant("separation"); + + Ref<StyleBox> sb=get_stylebox("frame"); + Ref<Texture> port =get_icon("port"); + conn_input_cache.clear(); + conn_output_cache.clear(); + int vofs=0; + + 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; + + Size2i size=c->get_combined_minimum_size(); + + int y = sb->get_margin(MARGIN_TOP)+vofs; + int h = size.y; + + + if (slot_info.has(idx)) { + + if (slot_info[idx].enable_left) { + ConnCache cc; + cc.pos=Point2i(edgeofs,y+h/2); + cc.type=slot_info[idx].type_left; + cc.color=slot_info[idx].color_left; + conn_input_cache.push_back(cc); + } + if (slot_info[idx].enable_right) { + ConnCache cc; + cc.pos=Point2i(get_size().width-edgeofs,y+h/2); + cc.type=slot_info[idx].type_right; + cc.color=slot_info[idx].color_right; + conn_output_cache.push_back(cc); + } + } + + if (vofs>0) + vofs+=sep; + vofs+=size.y; + idx++; + + } + + + connpos_dirty=false; +} + +int GraphNode::get_connection_input_count() { + + if (connpos_dirty) + _connpos_update(); + + return conn_input_cache.size(); + +} +int GraphNode::get_connection_output_count() { + + if (connpos_dirty) + _connpos_update(); + + return conn_output_cache.size(); + +} + + +Vector2 GraphNode::get_connection_input_pos(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Vector2()); + return conn_input_cache[p_idx].pos; +} + +int GraphNode::get_connection_input_type(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),0); + return conn_input_cache[p_idx].type; +} + +Color GraphNode::get_connection_input_color(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_input_cache.size(),Color()); + return conn_input_cache[p_idx].color; +} + +Vector2 GraphNode::get_connection_output_pos(int p_idx){ + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Vector2()); + return conn_output_cache[p_idx].pos; + +} + +int GraphNode::get_connection_output_type(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),0); + return conn_output_cache[p_idx].type; +} + +Color GraphNode::get_connection_output_color(int p_idx) { + + if (connpos_dirty) + _connpos_update(); + + ERR_FAIL_INDEX_V(p_idx,conn_output_cache.size(),Color()); + return conn_output_cache[p_idx].color; +} + +void GraphNode::_input_event(const InputEvent& p_ev) { + + if (p_ev.type==InputEvent::MOUSE_BUTTON && p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { + + Vector2 mpos = Vector2(p_ev.mouse_button.x,p_ev.mouse_button.y); + if (close_rect.size!=Size2() && close_rect.has_point(mpos)) { + emit_signal("close_request"); + return; + } + + drag_from=get_offset(); + drag_accum=Vector2(); + dragging=true; + emit_signal("raise_request"); + + } + + if (p_ev.type==InputEvent::MOUSE_BUTTON && !p_ev.mouse_button.pressed && p_ev.mouse_button.button_index==BUTTON_LEFT) { + + dragging=false; + emit_signal("dragged",drag_from,get_offset()); //useful for undo/redo + } + + if (p_ev.type==InputEvent::MOUSE_MOTION && dragging) { + + drag_accum+=Vector2(p_ev.mouse_motion.relative_x,p_ev.mouse_motion.relative_y); + set_offset(drag_from+drag_accum); + } + +} + + +void GraphNode::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("set_title","title"),&GraphNode::set_title); + ObjectTypeDB::bind_method(_MD("get_title"),&GraphNode::get_title); + ObjectTypeDB::bind_method(_MD("_input_event"),&GraphNode::_input_event); + + ObjectTypeDB::bind_method(_MD("set_slot","idx","enable_left","type_left","color_left","enable_right","type_right","color_right"),&GraphNode::set_slot); + ObjectTypeDB::bind_method(_MD("clear_slot","idx"),&GraphNode::clear_slot); + ObjectTypeDB::bind_method(_MD("clear_all_slots","idx"),&GraphNode::clear_all_slots); + ObjectTypeDB::bind_method(_MD("is_slot_enabled_left","idx"),&GraphNode::is_slot_enabled_left); + ObjectTypeDB::bind_method(_MD("get_slot_type_left","idx"),&GraphNode::get_slot_type_left); + ObjectTypeDB::bind_method(_MD("get_slot_color_left","idx"),&GraphNode::get_slot_color_left); + ObjectTypeDB::bind_method(_MD("is_slot_enabled_right","idx"),&GraphNode::is_slot_enabled_right); + ObjectTypeDB::bind_method(_MD("get_slot_type_right","idx"),&GraphNode::get_slot_type_right); + ObjectTypeDB::bind_method(_MD("get_slot_color_right","idx"),&GraphNode::get_slot_color_right); + + ObjectTypeDB::bind_method(_MD("set_offset","offset"),&GraphNode::set_offset); + ObjectTypeDB::bind_method(_MD("get_offset"),&GraphNode::get_offset); + + ObjectTypeDB::bind_method(_MD("get_connection_output_count"),&GraphNode::get_connection_output_count); + ObjectTypeDB::bind_method(_MD("get_connection_input_count"),&GraphNode::get_connection_input_count); + + ObjectTypeDB::bind_method(_MD("get_connection_output_pos","idx"),&GraphNode::get_connection_output_pos); + ObjectTypeDB::bind_method(_MD("get_connection_output_type","idx"),&GraphNode::get_connection_output_type); + ObjectTypeDB::bind_method(_MD("get_connection_output_color","idx"),&GraphNode::get_connection_output_color); + ObjectTypeDB::bind_method(_MD("get_connection_input_pos","idx"),&GraphNode::get_connection_input_pos); + ObjectTypeDB::bind_method(_MD("get_connection_input_type","idx"),&GraphNode::get_connection_input_type); + ObjectTypeDB::bind_method(_MD("get_connection_input_color","idx"),&GraphNode::get_connection_input_color); + + + ObjectTypeDB::bind_method(_MD("set_show_close_button","show"),&GraphNode::set_show_close_button); + ObjectTypeDB::bind_method(_MD("is_close_button_visible"),&GraphNode::is_close_button_visible); + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"title"),_SCS("set_title"),_SCS("get_title")); + ADD_PROPERTY( PropertyInfo(Variant::BOOL,"show_close"),_SCS("set_show_close_button"),_SCS("is_close_button_visible")); + + ADD_SIGNAL(MethodInfo("offset_changed")); + ADD_SIGNAL(MethodInfo("dragged",PropertyInfo(Variant::VECTOR2,"from"),PropertyInfo(Variant::VECTOR2,"to"))); + ADD_SIGNAL(MethodInfo("raise_request")); + ADD_SIGNAL(MethodInfo("close_request")); +} + +GraphNode::GraphNode() { + + dragging=false; + show_close=false; + connpos_dirty=true; +} diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h new file mode 100644 index 0000000000..0d5cbf8dd3 --- /dev/null +++ b/scene/gui/graph_node.h @@ -0,0 +1,101 @@ +#ifndef GRAPH_NODE_H +#define GRAPH_NODE_H + +#include "scene/gui/container.h" + +class GraphNode : public Container { + + OBJ_TYPE(GraphNode,Container); + + + + struct Slot { + bool enable_left; + int type_left; + Color color_left; + bool enable_right; + int type_right; + Color color_right; + + + Slot() { enable_left=false; type_left=0; color_left=Color(1,1,1,1); enable_right=false; type_right=0; color_right=Color(1,1,1,1); }; + }; + + String title; + bool show_close; + Vector2 offset; + + Rect2 close_rect; + + Vector<int> cache_y; + + struct ConnCache { + Vector2 pos; + int type; + Color color; + }; + + Vector<ConnCache> conn_input_cache; + Vector<ConnCache> conn_output_cache; + + Map<int,Slot> slot_info; + + bool connpos_dirty; + + void _connpos_update(); + void _resort(); + + Vector2 drag_from; + Vector2 drag_accum; + bool dragging; +protected: + + void _input_event(const InputEvent& p_ev); + void _notification(int p_what); + static void _bind_methods(); + + 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; + +public: + + + + + void set_slot(int p_idx,bool p_enable_left,int p_type_left,const Color& p_color_left, bool p_enable_right,int p_type_right,const Color& p_color_right); + void clear_slot(int p_idx); + void clear_all_slots(); + bool is_slot_enabled_left(int p_idx) const; + int get_slot_type_left(int p_idx) const; + Color get_slot_color_left(int p_idx) const; + bool is_slot_enabled_right(int p_idx) const; + int get_slot_type_right(int p_idx) const; + Color get_slot_color_right(int p_idx) const; + + void set_title(const String& p_title); + String get_title() const; + + void set_offset(const Vector2& p_offset); + Vector2 get_offset() const; + + void set_show_close_button(bool p_enable); + bool is_close_button_visible() const; + + int get_connection_input_count() ; + int get_connection_output_count() ; + Vector2 get_connection_input_pos(int p_idx); + int get_connection_input_type(int p_idx); + Color get_connection_input_color(int p_idx); + Vector2 get_connection_output_pos(int p_idx); + int get_connection_output_type(int p_idx); + Color get_connection_output_color(int p_idx); + + + virtual Size2 get_minimum_size() const; + + GraphNode(); +}; + + +#endif // GRAPH_NODE_H diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp index f54345cdb8..582693eb3a 100644 --- a/scene/gui/grid_container.cpp +++ b/scene/gui/grid_container.cpp @@ -226,5 +226,6 @@ Size2 GridContainer::get_minimum_size() const { GridContainer::GridContainer() { + set_stop_mouse(false); columns=1; } diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp index b7918994d8..d2e1e7f0b9 100644 --- a/scene/gui/label.cpp +++ b/scene/gui/label.cpp @@ -339,7 +339,7 @@ int Label::get_longest_line_width() const { int Label::get_line_count() const { - if (!is_inside_scene()) + if (!is_inside_tree()) return 1; if (word_cache_dirty) const_cast<Label*>(this)->regenerate_word_cache(); @@ -397,6 +397,7 @@ void Label::regenerate_word_cache() { } + if (current=='\n') { insert_newline=true; } else { @@ -446,7 +447,7 @@ void Label::regenerate_word_cache() { } - total_char_cache -= line_count + 1; // do not count new lines (including the first one) + //total_char_cache -= line_count + 1; // do not count new lines (including the first one) if (!autowrap) { @@ -535,7 +536,7 @@ 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); + set_visible_characters(get_total_character_count()*p_percent); percent_visible=p_percent; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index a77a40327f..68c990033a 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -572,7 +572,7 @@ void LineEdit::set_cursor_pos(int p_pos) { // set_window_pos(cursor_pos-get_window_lengt//h()); // } - if (!is_inside_scene()) { + if (!is_inside_tree()) { window_pos=cursor_pos; return; diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp index 7353744d07..d10ca20fc3 100644 --- a/scene/gui/menu_button.cpp +++ b/scene/gui/menu_button.cpp @@ -84,6 +84,7 @@ void MenuButton::pressed() { popup->set_parent_rect( Rect2(Point2(gp-popup->get_global_pos()),get_size())); popup->popup(); popup->call_deferred("grab_click_focus"); + popup->set_invalidate_click_until_motion(); } diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp index fa4a313115..78cc1bcdef 100644 --- a/scene/gui/option_button.cpp +++ b/scene/gui/option_button.cpp @@ -192,7 +192,7 @@ void OptionButton::_select(int p_idx,bool p_emit) { set_text( popup->get_item_text( current ) ); set_icon( popup->get_item_icon( current ) ); - if (is_inside_scene() && p_emit) + if (is_inside_tree() && p_emit) emit_signal("item_selected",current); } diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp index 65ad02723c..bccd05d4fe 100644 --- a/scene/gui/popup.cpp +++ b/scene/gui/popup.cpp @@ -51,11 +51,18 @@ void Popup::_fix_size() { Control *window = get_window(); ERR_FAIL_COND(!window); - + +#if 0 Point2 pos = get_pos(); Size2 size = get_size(); Point2 window_size = window==this ? get_parent_area_size() :window->get_size(); +#else + + Point2 pos = get_global_pos(); + Size2 size = get_size(); + Point2 window_size = get_viewport_rect().size; +#endif if (pos.x+size.width > window_size.width) pos.x=window_size.width-size.width; if (pos.x<0) @@ -65,8 +72,14 @@ void Popup::_fix_size() { pos.y=window_size.height-size.height; if (pos.y<0) pos.y=0; +#if 0 if (pos!=get_pos()) set_pos(pos); +#else + if (pos!=get_pos()) + set_global_pos(pos); + +#endif } diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index c2dc1318c9..1fd1d8adc8 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -30,6 +30,7 @@ #include "print_string.h" #include "os/keyboard.h" #include "translation.h" +#include "os/input.h" String PopupMenu::_get_accel_text(uint32_t p_accel) const { @@ -318,6 +319,10 @@ void PopupMenu::_input_event(const InputEvent &p_event) { int over=_get_mouse_over(Point2(b.x,b.y)); + if (invalidated_click) { + invalidated_click=false; + break; + } if (over<0 || items[over].separator || items[over].disabled) break; //non-activable @@ -336,6 +341,13 @@ void PopupMenu::_input_event(const InputEvent &p_event) { case InputEvent::MOUSE_MOTION: { + if (invalidated_click) { + moved+=Vector2(p_event.mouse_motion.relative_x,p_event.mouse_motion.relative_y); + if (moved.length()>4) + invalidated_click=false; + + } + const InputEventMouseMotion &m=p_event.mouse_motion; for(List<Rect2>::Element *E=autohide_areas.front();E;E=E->next()) { @@ -855,7 +867,7 @@ void PopupMenu::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_item","label","id","accel"),&PopupMenu::add_item,DEFVAL(-1),DEFVAL(0)); ObjectTypeDB::bind_method(_MD("add_icon_check_item","texture","label","id","accel"),&PopupMenu::add_icon_check_item,DEFVAL(-1),DEFVAL(0)); ObjectTypeDB::bind_method(_MD("add_check_item","label","id","accel"),&PopupMenu::add_check_item,DEFVAL(-1),DEFVAL(0)); - ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_check_item,DEFVAL(-1)); + ObjectTypeDB::bind_method(_MD("add_submenu_item","label","submenu","id"),&PopupMenu::add_submenu_item,DEFVAL(-1)); ObjectTypeDB::bind_method(_MD("set_item_text","idx","text"),&PopupMenu::set_item_text); ObjectTypeDB::bind_method(_MD("set_item_icon","idx","icon"),&PopupMenu::set_item_icon); ObjectTypeDB::bind_method(_MD("set_item_accelerator","idx","accel"),&PopupMenu::set_item_accelerator); @@ -893,12 +905,17 @@ void PopupMenu::_bind_methods() { } + +void PopupMenu::set_invalidate_click_until_motion() { + moved=Vector2(); + invalidated_click=true; +} + PopupMenu::PopupMenu() { idcount=0; mouse_over=-1; - set_focus_mode(FOCUS_ALL); set_as_toplevel(true); diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h index b150be1008..c2e988de95 100644 --- a/scene/gui/popup_menu.h +++ b/scene/gui/popup_menu.h @@ -70,6 +70,8 @@ class PopupMenu : public Popup { void _activate_submenu(int over); void _submenu_timeout(); + bool invalidated_click; + Vector2 moved; Array _get_items() const; void _set_items(const Array& p_items); @@ -134,6 +136,8 @@ public: void add_autohide_area(const Rect2& p_area); void clear_autohide_areas(); + void set_invalidate_click_until_motion(); + PopupMenu(); ~PopupMenu(); diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp index bc0fa9675e..4d0b678925 100644 --- a/scene/gui/range.cpp +++ b/scene/gui/range.cpp @@ -42,7 +42,7 @@ void Range::Shared::emit_value_changed() { for (Set<Range*>::Element *E=owners.front();E;E=E->next()) { Range *r=E->get(); - if (!r->is_inside_scene()) + if (!r->is_inside_tree()) continue; r->_value_changed_notify(); } @@ -59,7 +59,7 @@ void Range::Shared::emit_changed() { for (Set<Range*>::Element *E=owners.front();E;E=E->next()) { Range *r=E->get(); - if (!r->is_inside_scene()) + if (!r->is_inside_tree()) continue; r->_changed_notify(); } diff --git a/scene/gui/reference_frame.cpp b/scene/gui/reference_frame.cpp index 679c2cc1e2..44ba3a8972 100644 --- a/scene/gui/reference_frame.cpp +++ b/scene/gui/reference_frame.cpp @@ -32,9 +32,9 @@ void ReferenceFrame::_notification(int p_what) { if (p_what==NOTIFICATION_DRAW) { - if (!is_inside_scene()) + if (!is_inside_tree()) return; - if (get_scene()->is_editor_hint()) + if (get_tree()->is_editor_hint()) draw_style_box(get_stylebox("border"),Rect2(Point2(),get_size())) ; } } diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index c661a804b3..aaf96114c6 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -293,7 +293,7 @@ void ScrollBar::_notification(int p_what) { } - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { if (has_node(drag_slave_path)) { @@ -303,16 +303,16 @@ void ScrollBar::_notification(int p_what) { if (drag_slave) { drag_slave->connect("input_event",this,"_drag_slave_input"); - drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT); + drag_slave->connect("exit_tree",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT); } } - if (p_what==NOTIFICATION_EXIT_SCENE) { + if (p_what==NOTIFICATION_EXIT_TREE) { if (drag_slave) { drag_slave->disconnect("input_event",this,"_drag_slave_input"); - drag_slave->disconnect("exit_scene",this,"_drag_slave_exit"); + drag_slave->disconnect("exit_tree",this,"_drag_slave_exit"); } drag_slave=NULL; @@ -635,18 +635,18 @@ void ScrollBar::_drag_slave_input(const InputEvent& p_input) { void ScrollBar::set_drag_slave(const NodePath& p_path) { - if (is_inside_scene()) { + if (is_inside_tree()) { if (drag_slave) { drag_slave->disconnect("input_event",this,"_drag_slave_input"); - drag_slave->disconnect("exit_scene",this,"_drag_slave_exit"); + drag_slave->disconnect("exit_tree",this,"_drag_slave_exit"); } } drag_slave=NULL; drag_slave_path=p_path; - if (is_inside_scene()) { + if (is_inside_tree()) { if (has_node(p_path)) { Node *n = get_node(p_path); @@ -655,7 +655,7 @@ void ScrollBar::set_drag_slave(const NodePath& p_path) { if (drag_slave) { drag_slave->connect("input_event",this,"_drag_slave_input"); - drag_slave->connect("exit_scene",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT); + drag_slave->connect("exit_tree",this,"_drag_slave_exit",varray(),CONNECT_ONESHOT); } } } diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp index c8f9ed16b5..95354df519 100644 --- a/scene/gui/scroll_container.cpp +++ b/scene/gui/scroll_container.cpp @@ -169,7 +169,7 @@ void ScrollContainer::_update_scrollbar_pos() { void ScrollContainer::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_SCENE || p_what == NOTIFICATION_THEME_CHANGED) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { call_deferred("_update_scrollbar_pos"); }; diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp index 59f4386996..9ac67e92f5 100644 --- a/scene/gui/spin_box.cpp +++ b/scene/gui/spin_box.cpp @@ -122,7 +122,7 @@ void SpinBox::_notification(int p_what) { //_value_changed(0); - } else if (p_what==NOTIFICATION_ENTER_SCENE) { + } else if (p_what==NOTIFICATION_ENTER_TREE) { _value_changed(0); } diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp index 2d6f3cd27a..12a8a83f26 100644 --- a/scene/gui/tab_container.cpp +++ b/scene/gui/tab_container.cpp @@ -602,6 +602,39 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const { } +Size2 TabContainer::get_minimum_size() const { + + Size2 ms; + + 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 (!c->has_meta("_tab_name")) + continue; + + if (!c->is_visible()) + continue; + + Size2 cms = c->get_minimum_size(); + ms.x=MAX(ms.x,cms.x); + ms.y=MAX(ms.y,cms.y); + } + + Ref<StyleBox> tab_bg = get_stylebox("tab_bg"); + Ref<StyleBox> tab_fg = get_stylebox("tab_fg"); + Ref<Font> font = get_font("font"); + + ms.y+=MAX(tab_bg->get_minimum_size().y,tab_fg->get_minimum_size().y); + ms.y+=font->get_height(); + + return ms; +} + void TabContainer::_bind_methods() { ObjectTypeDB::bind_method(_MD("_input_event"),&TabContainer::_input_event); diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h index d5b6a2b503..df7b03e040 100644 --- a/scene/gui/tab_container.h +++ b/scene/gui/tab_container.h @@ -85,6 +85,8 @@ public: void set_current_tab(int p_current); int get_current_tab() const; + virtual Size2 get_minimum_size() const; + virtual void get_translatable_strings(List<String> *p_strings) const; TabContainer(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 6aabfa35a8..8855627bb4 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -26,7 +26,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ - /*****f********************************************/ +/*****f********************************************/ /* text_edit.cpp */ /*************************************************/ /* This file is part of: */ @@ -40,38 +40,38 @@ #include "text_edit.h" #include "os/keyboard.h" #include "os/os.h" - + #include "globals.h" #include "message_queue.h" #define TAB_PIXELS static bool _is_text_char(CharType c) { - + return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; } static bool _is_symbol(CharType c) { - + return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); } static bool _is_pair_right_symbol(CharType c) { return - c == '"' || - c == '\'' || - c == ')' || - c == ']' || - c == '}'; + c == '"' || + c == '\'' || + c == ')' || + c == ']' || + c == '}'; } static bool _is_pair_left_symbol(CharType c) { return - c == '"' || - c == '\'' || - c == '(' || - c == '[' || - c == '{'; + c == '"' || + c == '\'' || + c == '(' || + c == '[' || + c == '{'; } static bool _is_pair_symbol(CharType c) { @@ -93,81 +93,81 @@ static CharType _get_right_pair_symbol(CharType c) { } void TextEdit::Text::set_font(const Ref<Font>& p_font) { - + font=p_font; } void TextEdit::Text::set_tab_size(int p_tab_size) { - + tab_size=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 len = text[p_line].data.length(); const CharType *str = text[p_line].data.c_str(); - + //update width - + for(int i=0;i<len;i++) { if (str[i]=='\t') { - + int left = w%tab_w; if (left==0) w+=tab_w; else w+=tab_w-w%tab_w; // is right... - + } else { - + w+=font->get_char_size(str[i],str[i+1]).width; } } - - + + text[p_line].width_cache=w; - + //update regions - + text[p_line].region_info.clear(); - + for(int i=0;i<len;i++) { - + if (!_is_symbol(str[i])) continue; if (str[i]=='\\') { i++; //skip quoted anything continue; } - + int left=len-i; - + for(int j=0;j<color_regions->size();j++) { - + const ColorRegion& cr=color_regions->operator [](j); - + /* BEGIN */ - + int lr=cr.begin_key.length(); if (lr==0 || lr>left) continue; - + const CharType* kc = cr.begin_key.c_str(); - + bool match=true; - + for(int k=0;k<lr;k++) { if (kc[k]!=str[i+k]) { match=false; break; } } - + if (match) { - + ColorRegionInfo cri; cri.end=false; cri.region=j; @@ -175,26 +175,26 @@ void TextEdit::Text::_update_line_cache(int p_line) const { i+=lr-1; break; } - + /* END */ - + lr=cr.end_key.length(); if (lr==0 || lr>left) continue; - + kc = cr.end_key.c_str(); - + match=true; - + for(int k=0;k<lr;k++) { if (kc[k]!=str[i+k]) { match=false; break; } } - + if (match) { - + ColorRegionInfo cri; cri.end=true; cri.region=j; @@ -202,72 +202,72 @@ void TextEdit::Text::_update_line_cache(int p_line) const { i+=lr-1; break; } - + } } - - + + } const Map<int,TextEdit::Text::ColorRegionInfo>& TextEdit::Text::get_color_region_info(int p_line) { - + Map<int,ColorRegionInfo> *cri=NULL; ERR_FAIL_INDEX_V(p_line,text.size(),*cri); //enjoy your crash - + if (text[p_line].width_cache==-1) { _update_line_cache(p_line); } - + return text[p_line].region_info; } int TextEdit::Text::get_line_width(int p_line) const { - + ERR_FAIL_INDEX_V(p_line,text.size(),-1); - + if (text[p_line].width_cache==-1) { _update_line_cache(p_line); } - + return text[p_line].width_cache; } void TextEdit::Text::clear_caches() { - + for(int i=0;i<text.size();i++) text[i].width_cache=-1; - + } void TextEdit::Text::clear() { - - + + text.clear();; insert(0,""); } int TextEdit::Text::get_max_width() const { //quite some work.. but should be fast enough. - + int max = 0; - + for(int i=0;i<text.size();i++) max=MAX(max,get_line_width(i)); return max; - + } void TextEdit::Text::set(int p_line,const String& p_text) { - + ERR_FAIL_INDEX(p_line,text.size()); - + text[p_line].width_cache=-1; text[p_line].data=p_text; } void TextEdit::Text::insert(int p_at,const String& p_text) { - + Line line; line.marked=false; line.breakpoint=false; @@ -276,114 +276,114 @@ void TextEdit::Text::insert(int p_at,const String& p_text) { text.insert(p_at,line); } void TextEdit::Text::remove(int p_at) { - + text.remove(p_at); } void TextEdit::_update_scrollbars() { - - + + Size2 size = get_size(); Size2 hmin = h_scroll->get_combined_minimum_size(); Size2 vmin = v_scroll->get_combined_minimum_size(); - - - + + + v_scroll->set_begin( Point2(size.width - vmin.width, cache.style_normal->get_margin(MARGIN_TOP)) ); v_scroll->set_end( Point2(size.width, size.height - cache.style_normal->get_margin(MARGIN_TOP) - cache.style_normal->get_margin(MARGIN_BOTTOM)) ); - + h_scroll->set_begin( Point2( 0, size.height - hmin.height) ); h_scroll->set_end( Point2(size.width-vmin.width, size.height) ); - - + + int hscroll_rows = ((hmin.height-1)/get_row_height())+1; int visible_rows = get_visible_rows(); - int total_rows = text.size() * cache.line_spacing; - + int total_rows = text.size(); + 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(); - + bool use_hscroll=true; bool use_vscroll=true; - + if (total_rows <= visible_rows && total_width <= visible_width) { //thanks yessopie for this clever bit of logic use_hscroll=false; use_vscroll=false; - + } else { - + if (total_rows > visible_rows && total_width <= visible_width - vscroll_pixels) { //thanks yessopie for this clever bit of logic use_hscroll=false; } - + if (total_rows <= visible_rows - hscroll_rows && total_width > visible_width) { //thanks yessopie for this clever bit of logic use_vscroll=false; } } - + updating_scrolls=true; - + if (use_vscroll) { - + v_scroll->show(); v_scroll->set_max(total_rows); v_scroll->set_page(visible_rows); - + v_scroll->set_val(cursor.line_ofs); - + } else { cursor.line_ofs = 0; v_scroll->hide(); } - + if (use_hscroll) { - + h_scroll->show(); h_scroll->set_max(total_width); h_scroll->set_page(visible_width); h_scroll->set_val(cursor.x_ofs); } else { - + h_scroll->hide(); } - - - + + + updating_scrolls=false; } void TextEdit::_notification(int p_what) { - + switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { - + case NOTIFICATION_ENTER_TREE: { + _update_caches(); if (cursor_changed_dirty) MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); if (text_changed_dirty) MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); - + } break; case NOTIFICATION_RESIZED: { - + cache.size=get_size(); adjust_viewport_to_cursor(); - - + + } break; case NOTIFICATION_THEME_CHANGED: { - + _update_caches(); }; case NOTIFICATION_DRAW: { - + int line_number_char_count=0; - + { int lc=text.size()+1; cache.line_number_w=0; @@ -391,20 +391,20 @@ void TextEdit::_notification(int p_what) { cache.line_number_w+=1; lc/=10; }; - + if (line_numbers) { - + line_number_char_count=cache.line_number_w; cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width; } else { cache.line_number_w=0; } - - + + } _update_scrollbars(); - - + + RID ci = get_canvas_item(); int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w; int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT); @@ -412,77 +412,188 @@ void TextEdit::_notification(int p_what) { cache.style_normal->draw(ci,Rect2(Point2(),cache.size)); if (has_focus()) cache.style_focus->draw(ci,Rect2(Point2(),cache.size)); - - + + int ascent=cache.font->get_ascent(); - + int visible_rows = get_visible_rows(); - + int tab_w = cache.font->get_char_size(' ').width*tab_size; - + Color color = cache.font_color; int in_region=-1; - + if (syntax_coloring) { - + if (custom_bg_color.a>0.01) { - + Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0; VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color); } //compute actual region to start (may be inside say, a comment). //slow in very large documments :( but ok for source! - + for(int i=0;i<cursor.line_ofs;i++) { - + const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i); - + if (in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } - + for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) { - + const Text::ColorRegionInfo &cri=E->get(); - + if (in_region==-1) { - + if (!cri.end) { - + in_region=cri.region; } } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise - + if (cri.end || color_regions[cri.region].eq) { - + in_region=-1; } } } } } - + + int brace_open_match_line=-1; + int brace_open_match_column=-1; + bool brace_open_matching=false; + bool brace_open_mismatch=false; + int brace_close_match_line=-1; + int brace_close_match_column=-1; + bool brace_close_matching=false; + bool brace_close_mismatch=false; + + + if (brace_matching_enabled) { + + if (cursor.column<text[cursor.line].length()) { + //check for open + CharType c = text[cursor.line][cursor.column]; + CharType closec=0; + + if (c=='[') { + closec=']'; + } else if (c=='{') { + closec='}'; + } else if (c=='(') { + closec=')'; + } + + if (closec!=0) { + + int stack=1; + + + for(int i=cursor.line;i<text.size();i++) { + + int from = i==cursor.line?cursor.column+1:0; + for(int j=from;j<text[i].length();j++) { + + CharType cc = text[i][j]; + if (cc==c) + stack++; + else if (cc==closec) + stack--; + + if (stack==0) { + brace_open_match_line=i; + brace_open_match_column=j; + brace_open_matching=true; + + break; + } + } + if (brace_open_match_line!=-1) + break; + } + + if (!brace_open_matching) + brace_open_mismatch=true; + + + } + } + + if (cursor.column>0) { + CharType c = text[cursor.line][cursor.column-1]; + CharType closec=0; + + + + if (c==']') { + closec='['; + } else if (c=='}') { + closec='{'; + } else if (c==')') { + closec='('; + } + + if (closec!=0) { + + int stack=1; + + + for(int i=cursor.line;i>=0;i--) { + + int from = i==cursor.line?cursor.column-2:text[i].length()-1; + for(int j=from;j>=0;j--) { + + CharType cc = text[i][j]; + if (cc==c) + stack++; + else if (cc==closec) + stack--; + + if (stack==0) { + brace_close_match_line=i; + brace_close_match_column=j; + brace_close_matching=true; + + break; + } + } + if (brace_close_match_line!=-1) + break; + } + + if (!brace_close_matching) + brace_close_mismatch=true; + + + } + + + } + } + + int deregion=0; //force it to clear inrgion Point2 cursor_pos; - + for (int i=0;i<visible_rows;i++) { - + int line=i+cursor.line_ofs; - + if (line<0 || line>=(int)text.size()) continue; - - - + const String &str=text[line]; - + int char_margin=xmargin_beg-cursor.x_ofs; int char_ofs=0; int ofs_y=i*get_row_height()+cache.line_spacing/2; bool prev_is_char=false; bool in_keyword=false; Color keyword_color; - + if (cache.line_number_w) { Color fcol = cache.font_color; fcol.a*=0.4; @@ -490,167 +601,191 @@ void TextEdit::_notification(int p_what) { while (fc.length() < line_number_char_count) { fc="0"+fc; } - + cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol); } - + const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line); - - + + if (text.is_marked(line)) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color); } - + if (text.is_breakpoint(line)) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color); } - - + + if (line==cursor.line) { - + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color); - + } for (int j=0;j<str.length();j++) { - + //look for keyword - + if (deregion>0) { deregion--; if (deregion==0) in_region=-1; } if (syntax_coloring && deregion==0) { - - + + color = cache.font_color; //reset //find keyword bool is_char = _is_text_char(str[j]); bool is_symbol=_is_symbol(str[j]); - + if (j==0 && in_region>=0 && color_regions[in_region].line_only) { in_region=-1; //reset regions that end at end of line } - + if (is_symbol && cri_map.has(j)) { - - + + const Text::ColorRegionInfo &cri=cri_map[j]; - + if (in_region==-1) { - + if (!cri.end) { - + in_region=cri.region; } } else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise - + if (cri.end || color_regions[cri.region].eq) { - + deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length(); } } } - + if (!is_char) in_keyword=false; - + if (in_region==-1 && !in_keyword && is_char && !prev_is_char) { - + int to=j; while(_is_text_char(str[to]) && to<str.length()) to++; - + uint32_t hash = String::hash(&str[j],to-j); StrRange range(&str[j],to-j); - + const Color *col=keywords.custom_getptr(range,hash); - + if (col) { - + in_keyword=true; keyword_color=*col; } } - - + + if (in_region>=0) color=color_regions[in_region].color; else if (in_keyword) color=keyword_color; else if (is_symbol) color=symbol_color; - + prev_is_char=is_char; - + } int char_w; - + //handle tabulator - - + + if (str[j]=='\t') { int left = char_ofs%tab_w; if (left==0) char_w=tab_w; else char_w=tab_w-char_ofs%tab_w; // is right... - + } else { char_w=cache.font->get_char_size(str[j],str[j+1]).width; } - + if ( (char_ofs+char_margin)<xmargin_beg) { char_ofs+=char_w; continue; } - + if ( (char_ofs+char_margin+char_w)>=xmargin_end) { if (syntax_coloring) continue; else break; } - + bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column)); - - + + if (in_selection) { //inside selection! VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color); } - - - + + + if (brace_matching_enabled) { + if ( (brace_open_match_line==line && brace_open_match_column==j) || + (cursor.column==j && cursor.line==line && (brace_open_matching||brace_open_mismatch))) { + + if (brace_open_mismatch) + color=cache.brace_mismatch_color; + cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color); + + } + + if ( + (brace_close_match_line==line && brace_close_match_column==j) || + (cursor.column==j+1 && cursor.line==line && (brace_close_matching||brace_close_mismatch))) { + + + if (brace_close_mismatch) + color=cache.brace_mismatch_color; + cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),'_',str[j+1],in_selection?cache.font_selected_color:color); + + } + } + + if (str[j]>=32) cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color); + else if (draw_tabs && str[j]=='\t') { int yofs= (get_row_height() - cache.tab_icon->get_height())/2; cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color); } - - + + if (cursor.column==j && cursor.line==line) { - + cursor_pos = Point2i( char_ofs+char_margin, ofs_y ); VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); - - + + } char_ofs+=char_w; - + } - + if (cursor.column==str.length() && cursor.line==line) { - + cursor_pos=Point2i( char_ofs+char_margin, ofs_y ); VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color); - + } } - + + if (completion_active) { // code completion box Ref<StyleBox> csb = get_stylebox("completion"); @@ -658,17 +793,18 @@ void TextEdit::_notification(int p_what) { int maxlines = get_constant("completion_lines"); int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x; Color existing = get_color("completion_existing"); + existing.a=0.2; int scrollw = get_constant("completion_scroll_width"); Color scrollc = get_color("completion_scroll_color"); - - - + + + int lines = MIN(completion_options.size(),maxlines); int w=0; int h=lines*get_row_height(); int nofs = cache.font->get_string_size(completion_base).width; - - + + if (completion_options.size() < 50) { for(int i=0;i<completion_options.size();i++) { int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width); @@ -678,67 +814,135 @@ void TextEdit::_notification(int p_what) { } else { w=cmax_width; } - + int th = h + csb->get_minimum_size().y; if (cursor_pos.y+get_row_height()+th > get_size().height) { completion_rect.pos.y=cursor_pos.y-th; } else { completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y; + } - + if (cursor_pos.x-nofs+w+scrollw > get_size().width) { completion_rect.pos.x=get_size().width-w-scrollw; } else { completion_rect.pos.x=cursor_pos.x-nofs; } - - completion_rect.size.width=w; + + completion_rect.size.width=w+2; completion_rect.size.height=h; if (completion_options.size()<=maxlines) scrollw=0; - + draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0))); - - + + int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines); draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height()))); - + draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing); - + + + + for(int i=0;i<lines;i++) { - + int l = line_from + i; ERR_CONTINUE( l < 0 || l>= completion_options.size()); - draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width); + Color text_color = cache.font_color; + for(int j=0;j<color_regions.size();j++) { + if (completion_options[l].begins_with(color_regions[j].begin_key)) { + text_color=color_regions[j].color; + } + } + draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],text_color,completion_rect.size.width); } - + if (scrollw) { //draw a small scroll rectangle to show a position in the options float r = maxlines / (float)completion_options.size(); float o = line_from / (float)completion_options.size(); draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc); } - + completion_line_ofs=line_from; - + } - - - + + if (completion_hint!="") { + + Ref<StyleBox> sb = get_stylebox("panel","TooltipPanel"); + Ref<Font> font = cache.font; + Color font_color = get_color("font_color","TooltipLabel"); + + + int max_w=0; + int sc = completion_hint.get_slice_count("\n"); + int offset=0; + int spacing=0; + for(int i=0;i<sc;i++) { + + String l = completion_hint.get_slice("\n",i); + int len = font->get_string_size(l).x; + max_w = MAX(len,max_w); + if (i==0) { + offset = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x; + } else { + spacing+=cache.line_spacing; + } + + + } + + + + Size2 size = Size2(max_w,sc*font->get_height()+spacing); + Size2 minsize = size+sb->get_minimum_size(); + + + if (completion_hint_offset==-0xFFFF) { + completion_hint_offset=cursor_pos.x-offset; + } + + + Point2 hint_ofs = Vector2(completion_hint_offset,cursor_pos.y-minsize.y); + draw_style_box(sb,Rect2(hint_ofs,minsize)); + + spacing=0; + for(int i=0;i<sc;i++) { + int begin=0; + int end=0; + String l = completion_hint.get_slice("\n",i); + + if (l.find(String::chr(0xFFFF))!=-1) { + begin = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x; + end = font->get_string_size(l.substr(0,l.rfind(String::chr(0xFFFF)))).x; + } + + draw_string(font,hint_ofs+sb->get_offset()+Vector2(0,font->get_ascent()+font->get_height()*i+spacing),l.replace(String::chr(0xFFFF),""),font_color); + if (end>0) { + Vector2 b = hint_ofs+sb->get_offset()+Vector2(begin,font->get_height()+font->get_height()*i+spacing-1); + draw_line(b,b+Vector2(end-begin,0),font_color); + } + spacing+=cache.line_spacing; + } + } + + } break; case NOTIFICATION_FOCUS_ENTER: { - + if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect()); - + } break; case NOTIFICATION_FOCUS_EXIT: { - + if (OS::get_singleton()->has_virtual_keyboard()) OS::get_singleton()->hide_virtual_keyboard(); - + } break; - + } } @@ -750,23 +954,23 @@ void TextEdit::_consume_pair_symbol(CharType ch) { CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0}; CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0}; - if(is_selection_active()) { + if(is_selection_active()) { int new_column,new_line; _begin_compex_operation(); _insert_text(get_selection_from_line(), get_selection_from_column(), - ch_single, - &new_line, &new_column); + ch_single, + &new_line, &new_column); int to_col_offset = 0; - if(get_selection_from_line() == get_selection_to_line()) + if(get_selection_from_line() == get_selection_to_line()) to_col_offset = 1; - _insert_text(get_selection_to_line(), - get_selection_to_column() + to_col_offset, - ch_single_pair, - &new_line,&new_column); + _insert_text(get_selection_to_line(), + get_selection_to_column() + to_col_offset, + ch_single_pair, + &new_line,&new_column); _end_compex_operation(); cursor_set_line(get_selection_to_line()); @@ -778,9 +982,9 @@ void TextEdit::_consume_pair_symbol(CharType ch) { } if( (ch == '\'' || ch == '"') && - cursor_get_column() > 0 && - _is_text_char(text[cursor.line][cursor_get_column() - 1]) - ) { + cursor_get_column() > 0 && + _is_text_char(text[cursor.line][cursor_get_column() - 1]) + ) { insert_text_at_cursor(ch_single); cursor_set_column(cursor_position_to_move); return; @@ -792,9 +996,9 @@ void TextEdit::_consume_pair_symbol(CharType ch) { cursor_set_column(cursor_position_to_move); return; } - if( _is_pair_right_symbol(ch) && - text[cursor.line][cursor_get_column()] == ch - ) { + if( _is_pair_right_symbol(ch) && + text[cursor.line][cursor_get_column()] == ch + ) { cursor_set_column(cursor_position_to_move); return; } @@ -830,88 +1034,90 @@ void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column } void TextEdit::backspace_at_cursor() { + if (readonly) + return; if (cursor.column==0 && cursor.line==0) return; - + int prev_line = cursor.column?cursor.line:cursor.line-1; int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length()); - if(auto_brace_completion_enabled && - cursor.column > 0 && - _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { + if(auto_brace_completion_enabled && + cursor.column > 0 && + _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { _consume_backspace_for_pair_symbol(prev_line, prev_column); } else { _remove_text(prev_line,prev_column,cursor.line,cursor.column); } - + cursor_set_line(prev_line); cursor_set_column(prev_column); - + } bool TextEdit::_get_mouse_pos(const Point2i& p_mouse, int &r_row, int &r_col) const { - + int row=p_mouse.y; row-=cache.style_normal->get_margin(MARGIN_TOP); row/=get_row_height(); - + if (row<0 || row>=get_visible_rows()) return false; - + row+=cursor.line_ofs; int col=0; - + if (row>=text.size()) { - + row=text.size()-1; col=text[row].size(); } else { - + col=p_mouse.x-(cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w); col+=cursor.x_ofs; col=get_char_pos_for( col, get_line(row) ); } - + r_row=row; r_col=col; return true; } void TextEdit::_input_event(const InputEvent& p_input_event) { - + switch(p_input_event.type) { - + case InputEvent::MOUSE_BUTTON: { - + const InputEventMouseButton &mb=p_input_event.mouse_button; - + if (completion_active && completion_rect.has_point(Point2(mb.x,mb.y))) { - + if (!mb.pressed) return; - + if (mb.button_index==BUTTON_WHEEL_UP) { if (completion_index>0) { completion_index--; completion_current=completion_options[completion_index]; update(); } - + } if (mb.button_index==BUTTON_WHEEL_DOWN) { - + if (completion_index<completion_options.size()-1) { completion_index++; completion_current=completion_options[completion_index]; update(); } } - + if (mb.button_index==BUTTON_LEFT) { - + completion_index=CLAMP(completion_line_ofs+(mb.y-completion_rect.pos.y)/get_row_height(),0,completion_options.size()-1); - + completion_current=completion_options[completion_index]; update(); if (mb.doubleclick) @@ -920,8 +1126,9 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { return; } else { _cancel_completion(); + _cancel_code_hint(); } - + if (mb.pressed) { if (mb.button_index==BUTTON_WHEEL_UP) { v_scroll->set_val( v_scroll->get_val() -3 ); @@ -930,228 +1137,268 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { v_scroll->set_val( v_scroll->get_val() +3 ); } if (mb.button_index==BUTTON_LEFT) { - + int row,col; if (!_get_mouse_pos(Point2i(mb.x,mb.y), row,col)) return; - + int prev_col=cursor.column; int prev_line=cursor.line; + + + + cursor_set_line( row ); + cursor_set_column( col ); + + if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) { + if (!selection.active) { + selection.active=true; + selection.selecting_mode=Selection::MODE_POINTER; + selection.from_column=prev_col; + selection.from_line=prev_line; + selection.to_column=cursor.column; + selection.to_line=cursor.line; + if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) { + SWAP(selection.from_column,selection.to_column); + SWAP(selection.from_line,selection.to_line); + selection.shiftclick_left=false; + } else { + selection.shiftclick_left=true; + } + selection.selecting_line=prev_line; + selection.selecting_column=prev_col; + update(); + } else { - cursor_set_line( row ); - cursor_set_column( col ); + if (cursor.line<selection.from_line || (cursor.line==selection.from_line && cursor.column<=selection.from_column)) { + selection.from_column=cursor.column; + selection.from_line=cursor.line; + } else if (cursor.line>selection.to_line || (cursor.line==selection.to_line && cursor.column>=selection.to_column)) { + selection.to_column=cursor.column; + selection.to_line=cursor.line; - if (mb.mod.shift && (cursor.column!=prev_col || cursor.line!=prev_line)) { + } else if (!selection.shiftclick_left) { - selection.active=true; - selection.selecting_mode=Selection::MODE_POINTER; - selection.from_column=prev_col; - selection.from_line=prev_line; - selection.to_column=cursor.column; - selection.to_line=cursor.line; - if (selection.from_column>selection.to_column) { - SWAP(selection.from_column,selection.to_column); - SWAP(selection.from_line,selection.to_line); + selection.from_column=cursor.column; + selection.from_line=cursor.line; + } else { + + selection.to_column=cursor.column; + selection.to_line=cursor.line; + } + + if (selection.from_line>selection.to_line || (selection.from_line==selection.to_line && selection.from_column>selection.to_column)) { + SWAP(selection.from_column,selection.to_column); + SWAP(selection.from_line,selection.to_line); + } + update(); } - selection.selecting_line=prev_line; - selection.selecting_column=prev_col; - update(); - } else { - //if sel active and dblick last time < something - //else + + + + + } else { + + //if sel active and dblick last time < something + + //else selection.active=false; selection.selecting_mode=Selection::MODE_POINTER; selection.selecting_line=row; selection.selecting_column=col; } - - + + if (!mb.doubleclick && (OS::get_singleton()->get_ticks_msec()-last_dblclk)<600) { //tripleclick select line select(cursor.line,0,cursor.line,text[cursor.line].length()); last_dblclk=0; - + } else if (mb.doubleclick && text[cursor.line].length()) { - + //doubleclick select world String s = text[cursor.line]; int beg=CLAMP(cursor.column,0,s.length()); int end=beg; - + if (s[beg]>32 || beg==s.length()) { - + bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - + while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { beg--; } while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) { end++; } - + if (end<s.length()) end+=1; - + select(cursor.line,beg,cursor.line,end); } - + last_dblclk = OS::get_singleton()->get_ticks_msec(); - + } - + update(); } } else { - + selection.selecting_mode=Selection::MODE_NONE; - // notify to show soft keyboard - notification(NOTIFICATION_FOCUS_ENTER); + // notify to show soft keyboard + notification(NOTIFICATION_FOCUS_ENTER); } - + } break; - case InputEvent::MOUSE_MOTION: { - - const InputEventMouseMotion &mm=p_input_event.mouse_motion; - - if (mm.button_mask&BUTTON_MASK_LEFT) { - + case InputEvent::MOUSE_MOTION: { + + const InputEventMouseMotion &mm=p_input_event.mouse_motion; + + if (mm.button_mask&BUTTON_MASK_LEFT) { + int row,col; if (!_get_mouse_pos(Point2i(mm.x,mm.y), row,col)) return; - - if (selection.selecting_mode==Selection::MODE_POINTER) { - + + if (selection.selecting_mode==Selection::MODE_POINTER) { + select(selection.selecting_line,selection.selecting_column,row,col); - + cursor_set_line( row ); cursor_set_column( col ); update(); - - } - - } - - } break; - + + } + + } + + } break; + case InputEvent::KEY: { - + InputEventKey k=p_input_event.key; - + if (!k.pressed) return; - + if (completion_active) { + if (readonly) + break; bool valid=true; - if (k.mod.command || k.mod.alt || k.mod.meta) + if (k.mod.command || k.mod.meta) valid=false; - + if (valid) { + + if (!k.mod.alt) { + if (k.scancode==KEY_UP) { + + if (completion_index>0) { + completion_index--; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; + } + - if (k.scancode==KEY_UP) { + if (k.scancode==KEY_DOWN) { - if (completion_index>0) { - completion_index--; + if (completion_index<completion_options.size()-1) { + completion_index++; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; + } + + if (k.scancode==KEY_PAGEUP) { + + completion_index-=get_constant("completion_lines"); + if (completion_index<0) + completion_index=0; completion_current=completion_options[completion_index]; update(); + accept_event(); + return; } - accept_event(); - return; - } - if (k.scancode==KEY_DOWN) { + if (k.scancode==KEY_PAGEDOWN) { - if (completion_index<completion_options.size()-1) { - completion_index++; + completion_index+=get_constant("completion_lines"); + if (completion_index>=completion_options.size()) + completion_index=completion_options.size()-1; completion_current=completion_options[completion_index]; update(); + accept_event(); + return; } - accept_event(); - return; - } - if (k.scancode==KEY_PAGEUP) { + if (k.scancode==KEY_HOME) { - completion_index-=get_constant("completion_lines"); - if (completion_index<0) completion_index=0; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } - if (k.scancode==KEY_PAGEDOWN) { + if (k.scancode==KEY_END) { - completion_index+=get_constant("completion_lines"); - if (completion_index>=completion_options.size()) completion_index=completion_options.size()-1; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k.scancode==KEY_HOME) { - - completion_index=0; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } - - if (k.scancode==KEY_END) { - - completion_index=completion_options.size()-1; - completion_current=completion_options[completion_index]; - update(); - accept_event(); - return; - } + completion_current=completion_options[completion_index]; + update(); + accept_event(); + return; + } - if (k.scancode==KEY_DOWN) { + if (k.scancode==KEY_DOWN) { - if (completion_index<completion_options.size()-1) { - completion_index++; - completion_current=completion_options[completion_index]; - update(); + if (completion_index<completion_options.size()-1) { + completion_index++; + completion_current=completion_options[completion_index]; + update(); + } + accept_event(); + return; } - accept_event(); - return; - } - if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) { + if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) { - _confirm_completion(); - accept_event(); - return; - } + _confirm_completion(); + accept_event(); + return; + } - if (k.scancode==KEY_BACKSPACE) { + if (k.scancode==KEY_BACKSPACE) { - backspace_at_cursor(); - _update_completion_candidates(); - accept_event(); - return; - } + backspace_at_cursor(); + _update_completion_candidates(); + accept_event(); + return; + } - if (k.scancode==KEY_SHIFT) { - accept_event(); - return; + if (k.scancode==KEY_SHIFT) { + accept_event(); + return; + } } - + if (k.unicode>32) { - + if (cursor.column<text[cursor.line].length() && text[cursor.line][cursor.column]==k.unicode) { //same char, move ahead cursor_set_column(cursor.column+1); @@ -1165,48 +1412,52 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { _insert_text_at_cursor(chr); } } - + _update_completion_candidates(); accept_event(); - + return; } } - + _cancel_completion(); + } - + /* TEST CONTROL FIRST!! */ - + // some remaps for duplicate functions.. if (k.mod.command && !k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) { - + k.scancode=KEY_C; } if (!k.mod.command && k.mod.shift && !k.mod.alt && !k.mod.meta && k.scancode==KEY_INSERT) { - + k.scancode=KEY_V; k.mod.command=true; - k.mod.shift=false; + k.mod.shift=false; } - + // stuff to do when selection is active.. - + if (selection.active) { + if (readonly) + break; + bool clear=false; bool unselect=false; bool dobreak=false; - + switch(k.scancode) { - + case KEY_TAB: { - + String txt = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); String prev_txt=txt; - + if (k.mod.shift) { - + for(int i=0;i<txt.length();i++) { if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/)) && (txt[i]=='\t' || txt[i]==' ')) { txt.remove(i); @@ -1214,21 +1465,21 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } } } else { - + for(int i=0;i<txt.length();i++) { - + if (((i>0 && txt[i-1]=='\n') || (i==0 /*&& selection.from_column==0*/))) { txt=txt.insert(i,"\t"); //i--; } } } - + if (txt!=prev_txt) { - + int sel_line=selection.from_line; int sel_column=selection.from_column; - + cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); _begin_compex_operation(); @@ -1242,10 +1493,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { selection.to_line=cursor.line; update(); } - + dobreak=true; accept_event(); - + } break; case KEY_X: case KEY_C: @@ -1256,7 +1507,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { case KEY_BACKSPACE: accept_event(); clear=true; dobreak=true; - break; + break; case KEY_LEFT: case KEY_RIGHT: case KEY_UP: @@ -1265,24 +1516,26 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { case KEY_PAGEDOWN: case KEY_HOME: case KEY_END: - if (k.mod.shift) // if selecting ignore + // ignore arrows if any modifiers are held (shift = selecting, others may be used for editor hotkeys) + if (k.mod.command || k.mod.shift || k.mod.alt || k.mod.command) break; unselect=true; break; + default: if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta) clear=true; if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode)) clear=false; } - + if (unselect) { selection.active=false; selection.selecting_mode=Selection::MODE_NONE; update(); } if (clear) { - + selection.active=false; update(); _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); @@ -1293,20 +1546,23 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (dobreak) break; } - + selection.selecting_test=false; - + bool scancode_handled=true; - + // special scancode test... switch (k.scancode) { - + case KEY_ENTER: case KEY_RETURN: { - String ins="\n"; + if (readonly) + break; + String ins="\n"; + //keep indentation for(int i=0;i<text[cursor.line].length();i++) { if (text[cursor.line][i]=='\t') @@ -1314,26 +1570,33 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { else break; } - + _insert_text_at_cursor(ins); _push_current_op(); - + + } break; + case KEY_ESCAPE: { + if (completion_hint!="") { + completion_hint=""; + update(); + + } } break; case KEY_TAB: { - + if (readonly) break; - + if (selection.active) { - - + + } else { if (k.mod.shift) { - + int cc = cursor.column; if (cc>0 && cc<=text[cursor.line].length() && text[cursor.line][cursor.column-1]=='\t') { //simple unindent - + backspace_at_cursor(); } } else { @@ -1341,173 +1604,187 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { _insert_text_at_cursor("\t"); } } - + } break; case KEY_BACKSPACE: { if (readonly) break; backspace_at_cursor(); - + } break; case KEY_LEFT: { - + if (k.mod.shift) _pre_shift_selection(); - + #ifdef APPLE_STYLE_KEYS if (k.mod.command) { cursor_set_column(0); } else if (k.mod.alt) { - + #else - if (k.mod.command) { + if (k.mod.alt) { + scancode_handled=false; + break; + } else if (k.mod.command) { #endif bool prev_char=false; int cc=cursor.column; while (cc>0) { - + bool ischar=_is_text_char(text[cursor.line][cc-1]); - + if (prev_char && !ischar) break; - + prev_char=ischar; cc--; - + } - + cursor_set_column(cc); - - } else if (cursor.column==0) { - + + } else if (cursor.column==0) { + if (cursor.line>0) { cursor_set_line(cursor.line-1); cursor_set_column(text[cursor.line].length()); } - } else { + } else { cursor_set_column(cursor_get_column()-1); } - + if (k.mod.shift) _post_shift_selection(); - + } break; case KEY_RIGHT: { - + if (k.mod.shift) _pre_shift_selection(); - + #ifdef APPLE_STYLE_KEYS if (k.mod.command) { cursor_set_column(text[cursor.line].length()); } else if (k.mod.alt) { #else - if (k.mod.command) { + if (k.mod.alt) { + scancode_handled=false; + break; + } else if (k.mod.command) { #endif bool prev_char=false; int cc=cursor.column; while (cc<text[cursor.line].length()) { - + bool ischar=_is_text_char(text[cursor.line][cc]); - + if (prev_char && !ischar) break; prev_char=ischar; cc++; } - + cursor_set_column(cc); - - } else if (cursor.column==text[cursor.line].length()) { - + + } else if (cursor.column==text[cursor.line].length()) { + if (cursor.line<text.size()-1) { cursor_set_line(cursor.line+1); cursor_set_column(0); } - } else { + } else { cursor_set_column(cursor_get_column()+1); } - + if (k.mod.shift) _post_shift_selection(); - + } break; case KEY_UP: { - + if (k.mod.shift) _pre_shift_selection(); - + if (k.mod.alt) { + scancode_handled=false; + break; + } #ifdef APPLE_STYLE_KEYS if (k.mod.command) cursor_set_line(0); else #endif cursor_set_line(cursor_get_line()-1); - + if (k.mod.shift) _post_shift_selection(); - + _cancel_code_hint(); + } break; case KEY_DOWN: { - + if (k.mod.shift) _pre_shift_selection(); - + if (k.mod.alt) { + scancode_handled=false; + break; + } #ifdef APPLE_STYLE_KEYS if (k.mod.command) cursor_set_line(text.size()-1); else #endif cursor_set_line(cursor_get_line()+1); - + if (k.mod.shift) _post_shift_selection(); - + _cancel_code_hint(); + } break; - + case KEY_DELETE: { - + if (readonly) break; int curline_len = text[cursor.line].length(); - + if (cursor.line==text.size()-1 && cursor.column==curline_len) break; //nothing to do - + int next_line = cursor.column<curline_len?cursor.line:cursor.line+1; int next_column = cursor.column<curline_len?(cursor.column+1):0; _remove_text(cursor.line,cursor.column,next_line,next_column); update(); } break; #ifdef APPLE_STYLE_KEYS - case KEY_HOME: { - - - if (k.mod.shift) - _pre_shift_selection(); - - cursor_set_line(0); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - case KEY_END: { - - if (k.mod.shift) - _pre_shift_selection(); - - cursor_set_line(text.size()-1); - - if (k.mod.shift) - _post_shift_selection(); - - } break; - + case KEY_HOME: { + + + if (k.mod.shift) + _pre_shift_selection(); + + cursor_set_line(0); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + case KEY_END: { + + if (k.mod.shift) + _pre_shift_selection(); + + cursor_set_line(text.size()-1); + + if (k.mod.shift) + _post_shift_selection(); + + } break; + #else case KEY_HOME: { - - + + if (k.mod.shift) _pre_shift_selection(); @@ -1527,54 +1804,54 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (k.mod.command) cursor_set_line(0); - + if (k.mod.shift) _post_shift_selection(); - + } break; case KEY_END: { - + if (k.mod.shift) _pre_shift_selection(); - + if (k.mod.command) cursor_set_line(text.size()-1); cursor_set_column(text[cursor.line].length()); - + if (k.mod.shift) _post_shift_selection(); - + } break; #endif case KEY_PAGEUP: { - + if (k.mod.shift) _pre_shift_selection(); - + cursor_set_line(cursor_get_line()-get_visible_rows()); - + if (k.mod.shift) _post_shift_selection(); - + } break; case KEY_PAGEDOWN: { - + if (k.mod.shift) _pre_shift_selection(); - + cursor_set_line(cursor_get_line()+get_visible_rows()); - + if (k.mod.shift) _post_shift_selection(); - + } break; case KEY_A: { - + if (!k.mod.command || k.mod.shift || k.mod.alt) { scancode_handled=false; break; } - + if (text.size()==1 && text[0].length()==0) break; selection.active=true; @@ -1584,186 +1861,169 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { selection.to_column=text[selection.to_line].size(); selection.selecting_mode=Selection::MODE_NONE; update(); - + } break; case KEY_X: { - + if (!k.mod.command || k.mod.shift || k.mod.alt) { scancode_handled=false; break; } - - if (!selection.active){ - - String clipboard = text[cursor.line]; - OS::get_singleton()->set_clipboard(clipboard); - cursor_set_line(cursor.line); - cursor_set_column(0); - _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); - - backspace_at_cursor(); - update(); - cursor_set_line(cursor.line+1); - cut_copy_line = true; - - } - else - { - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); - - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); - cut_copy_line = false; - } - + + if (!selection.active){ + + String clipboard = text[cursor.line]; + OS::get_singleton()->set_clipboard(clipboard); + cursor_set_line(cursor.line); + cursor_set_column(0); + _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); + + backspace_at_cursor(); + update(); + cursor_set_line(cursor.line+1); + cut_copy_line = true; + + } + else + { + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + cut_copy_line = false; + } + } break; case KEY_C: { - + if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; + scancode_handled=false; + break; + } + + if (!selection.active){ + String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = true; + } + else{ + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = false; } - - if (!selection.active){ - String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); - OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = true; - } - else{ - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); - cut_copy_line = false; - } } break; case KEY_Z: { - - if (!k.mod.command) { - scancode_handled=false; - break; - } - - if (k.mod.shift) - redo(); - else - undo(); + + if (!k.mod.command) { + scancode_handled=false; + break; + } + + if (k.mod.shift) + redo(); + else + undo(); } break; case KEY_V: { - + if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; + scancode_handled=false; + break; } - + String clipboard = OS::get_singleton()->get_clipboard(); - + if (selection.active) { selection.active=false; _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); - + } - else if (cut_copy_line) - { - cursor_set_column(0); - String ins="\n"; - clipboard += ins; - } - + else if (cut_copy_line) + { + cursor_set_column(0); + String ins="\n"; + clipboard += ins; + } + _insert_text_at_cursor(clipboard); - + update(); } break; case KEY_SPACE: { +#ifdef OSX_ENABLED + if (completion_enabled && k.mod.meta) { //cmd-space is spotlight shortcut in OSX +#else if (completion_enabled && k.mod.command) { - +#endif + query_code_comple(); scancode_handled=true; } else { scancode_handled=false; } - + } break; - - case KEY_K:{ - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - else { - if (selection.active) { - int ini = selection.from_line; - int end = selection.to_line; - for (int i=ini; i<= end; i++) - { - _insert_text(i,0,"#"); - } - } - else{ - _insert_text(cursor.line,0,"#"); - } - update(); - } - break;} - - case KEY_U:{ - if (!k.mod.command || k.mod.shift || k.mod.alt) { - scancode_handled=false; - break; - } - else { - if (selection.active) { - int ini = selection.from_line; - int end = selection.to_line; - for (int i=ini; i<= end; i++) - { - if (text[i][0] == '#') - _remove_text(i,0,i,1); - } - } - else{ - if (text[cursor.line][0] == '#') - _remove_text(cursor.line,0,cursor.line,1); - } - update(); - } - break;} - - default: { - - scancode_handled=false; - } break; - - } - - if (scancode_handled) - accept_event(); - - if (!scancode_handled && !k.mod.command && !k.mod.alt) { - - if (k.unicode>=32) { - - if (readonly) + + case KEY_U:{ + if (!k.mod.command || k.mod.shift) { + scancode_handled=false; break; - - accept_event(); - } else { - - break; - } + } + else { + if (selection.active) { + int ini = selection.from_line; + int end = selection.to_line; + for (int i=ini; i<= end; i++) + { + if (text[i][0] == '#') + _remove_text(i,0,i,1); + } + } + else{ + if (text[cursor.line][0] == '#') + _remove_text(cursor.line,0,cursor.line,1); + } + update(); + } + break;} + + default: { + + scancode_handled=false; + } break; + } - if (!scancode_handled && !k.mod.command && !k.mod.alt) { + if (scancode_handled) + accept_event(); + /* + if (!scancode_handled && !k.mod.command && !k.mod.alt) { + + if (k.unicode>=32) { + + if (readonly) + break; + accept_event(); + } else { + + break; + } + } +*/ + if (!scancode_handled && !k.mod.command) { //for german kbds + if (k.unicode>=32) { - + if (readonly) break; @@ -1777,30 +2037,30 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { accept_event(); } else { - + break; } } - + if (!selection.selecting_test) { - + selection.selecting_mode=Selection::MODE_NONE; } - + return; } break; - + } - + } void TextEdit::_pre_shift_selection() { - - + + if (!selection.active || selection.selecting_mode!=Selection::MODE_SHIFT) { - + selection.selecting_line=cursor.line; selection.selecting_column=cursor.column; selection.active=true; @@ -1809,145 +2069,141 @@ void TextEdit::_pre_shift_selection() { } void TextEdit::_post_shift_selection() { - - + + if (selection.active && selection.selecting_mode==Selection::MODE_SHIFT) { - + select(selection.selecting_line,selection.selecting_column,cursor.line,cursor.column); update(); } - - + + selection.selecting_test=true; } /**** TEXT EDIT CORE API ****/ void TextEdit::_base_insert_text(int p_line, int p_char,const String& p_text,int &r_end_line,int &r_end_column) { - + //save for undo... ERR_FAIL_INDEX(p_line,text.size()); ERR_FAIL_COND(p_char<0); - + /* STEP 1 add spaces if the char is greater than the end of the line */ while(p_char>text[p_line].length()) { - + text.set(p_line,text[p_line]+String::chr(' ')); } - + /* STEP 2 separate dest string in pre and post text */ - + String preinsert_text = text[p_line].substr(0,p_char); String postinsert_text = text[p_line].substr(p_char,text[p_line].size()); - + /* STEP 3 remove \r from source text and separate in substrings */ - + //buh bye \r and split Vector<String> substrings = p_text.replace("\r","").split("\n"); - - + + for(int i=0;i<substrings.size();i++) { //insert the substrings - + if (i==0) { - + text.set(p_line,preinsert_text+substrings[i]); } else { - + text.insert(p_line+i,substrings[i]); } - + if (i==substrings.size()-1){ - + text.set(p_line+i,text[p_line+i]+postinsert_text); } } - + r_end_line=p_line+substrings.size()-1; r_end_column=text[r_end_line].length()-postinsert_text.length(); - + if (!text_changed_dirty && !setting_text) { - - if (is_inside_scene()) + if (is_inside_tree()) MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); text_changed_dirty=true; } - + } String TextEdit::_base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const { - + ERR_FAIL_INDEX_V(p_from_line,text.size(),String()); ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,String()); ERR_FAIL_INDEX_V(p_to_line,text.size(),String()); ERR_FAIL_INDEX_V(p_to_column,text[p_to_line].length()+1,String()); ERR_FAIL_COND_V(p_to_line < p_from_line ,String()); // from > to ERR_FAIL_COND_V(p_to_line == p_from_line && p_to_column<p_from_column,String()); // from > to - + String ret; - + for(int i=p_from_line;i<=p_to_line;i++) { - + int begin = (i==p_from_line)?p_from_column:0; int end = (i==p_to_line)?p_to_column:text[i].length(); - + if (i>p_from_line) ret+="\n"; ret+=text[i].substr(begin,end-begin); } - + return ret; } void TextEdit::_base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) { - + ERR_FAIL_INDEX(p_from_line,text.size()); ERR_FAIL_INDEX(p_from_column,text[p_from_line].length()+1); ERR_FAIL_INDEX(p_to_line,text.size()); ERR_FAIL_INDEX(p_to_column,text[p_to_line].length()+1); ERR_FAIL_COND(p_to_line < p_from_line ); // from > to ERR_FAIL_COND(p_to_line == p_from_line && p_to_column<p_from_column); // from > to - - + + String pre_text = text[p_from_line].substr(0,p_from_column); String post_text = text[p_to_line].substr(p_to_column,text[p_to_line].length()); - + for(int i=p_from_line;i<p_to_line;i++) { - + text.remove(p_from_line+1); } - + text.set(p_from_line,pre_text+post_text); - + if (!text_changed_dirty && !setting_text) { - - if (is_inside_scene()) + if (is_inside_tree()) MessageQueue::get_singleton()->push_call(this,"_text_changed_emit"); text_changed_dirty=true; } } - - void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_end_line,int *r_end_column) { - + if (!setting_text) idle_detect->start(); - + if (undo_enabled) { _clear_redo(); } - + int retline,retchar; _base_insert_text(p_line,p_char,p_text,retline,retchar); if (r_end_line) *r_end_line=retline; if (r_end_column) *r_end_column=retchar; - + if (!undo_enabled) return; - + /* UNDO!! */ TextOperation op; op.type=TextOperation::TYPE_INSERT; @@ -1959,12 +2215,12 @@ void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_e op.version=++version; op.chain_forward=false; op.chain_backward=false; - + //see if it shold just be set as current op if (current_op.type!=op.type) { _push_current_op(); current_op=op; - + return; //set as current op, return } //see if it can be merged @@ -1974,30 +2230,30 @@ void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_e return; //set as current op, return } //merge current op - + current_op.text+=p_text; current_op.to_column=retchar; current_op.to_line=retline; current_op.version=op.version; - + } void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) { - + if (!setting_text) idle_detect->start(); - + String text; if (undo_enabled) { _clear_redo(); text=_base_get_text(p_from_line,p_from_column,p_to_line,p_to_column); } - + _base_remove_text(p_from_line,p_from_column,p_to_line,p_to_column); - + if (!undo_enabled) return; - + /* UNDO!! */ TextOperation op; op.type=TextOperation::TYPE_REMOVE; @@ -2009,7 +2265,7 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int op.version=++version; op.chain_forward=false; op.chain_backward=false; - + //see if it shold just be set as current op if (current_op.type!=op.type) { _push_current_op(); @@ -2025,26 +2281,26 @@ void TextEdit::_remove_text(int p_from_line, int p_from_column,int p_to_line,int return; //update current op } if (current_op.from_line==p_from_line && current_op.from_column==p_from_column) { - + //current_op.text=text+current_op.text; //current_op.from_line=p_from_line; //current_op.from_column=p_from_column; //return; //update current op } - + _push_current_op(); current_op=op; - + } void TextEdit::_insert_text_at_cursor(const String& p_text) { - + int new_column,new_line; _insert_text(cursor.line,cursor.column,p_text,&new_line,&new_column); cursor_set_line(new_line); cursor_set_column(new_column); - + update(); } @@ -2052,145 +2308,143 @@ void TextEdit::_insert_text_at_cursor(const String& p_text) { int TextEdit::get_char_count() { - + int totalsize=0; - + for (int i=0;i<text.size();i++) { - + if (i>0) totalsize++; // incliude \n totalsize+=text[i].length(); } - + return totalsize; // omit last \n } Size2 TextEdit::get_minimum_size() { - + return cache.style_normal->get_minimum_size(); } int TextEdit::get_visible_rows() const { - + int total=cache.size.height; total-=cache.style_normal->get_minimum_size().height; total/=get_row_height(); return total; } void TextEdit::adjust_viewport_to_cursor() { - + if (cursor.line_ofs>cursor.line) cursor.line_ofs=cursor.line; - + int visible_width=cache.size.width-cache.style_normal->get_minimum_size().width-cache.line_number_w; if (v_scroll->is_visible()) visible_width-=v_scroll->get_combined_minimum_size().width; visible_width-=20; // give it a little more space - - + + //printf("rowofs %i, visrows %i, cursor.line %i\n",cursor.line_ofs,get_visible_rows(),cursor.line); - + int visible_rows = get_visible_rows(); if (h_scroll->is_visible()) visible_rows-=((h_scroll->get_combined_minimum_size().height-1)/get_row_height()); - + if (cursor.line>=(cursor.line_ofs+visible_rows)) cursor.line_ofs=cursor.line-visible_rows+1; if (cursor.line<cursor.line_ofs) cursor.line_ofs=cursor.line; - + int cursor_x = get_column_x_offset( cursor.column, text[cursor.line] ); - + if (cursor_x>(cursor.x_ofs+visible_width)) cursor.x_ofs=cursor_x-visible_width+1; - + if (cursor_x < cursor.x_ofs) cursor.x_ofs=cursor_x; - + update(); -/* - get_range()->set_max(text.size()); - - get_range()->set_page(get_visible_rows()); - - get_range()->set((int)cursor.line_ofs); + /* + get_range()->set_max(text.size()); + + get_range()->set_page(get_visible_rows()); + + get_range()->set((int)cursor.line_ofs); */ - - + + } void TextEdit::cursor_set_column(int p_col) { - + if (p_col<0) p_col=0; - + cursor.column=p_col; if (cursor.column > get_line( cursor.line ).length()) cursor.column=get_line( cursor.line ).length(); - + cursor.last_fit_x=get_column_x_offset(cursor.column,get_line(cursor.line)); - + adjust_viewport_to_cursor(); - + if (!cursor_changed_dirty) { - - if (is_inside_scene()) + if (is_inside_tree()) MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); cursor_changed_dirty=true; } - + } void TextEdit::cursor_set_line(int p_row) { - + if (setting_row) return; - + setting_row=true; if (p_row<0) p_row=0; - - + + if (p_row>=(int)text.size()) p_row=(int)text.size()-1; - + cursor.line=p_row; cursor.column=get_char_pos_for( cursor.last_fit_x, get_line( cursor.line) ); - - + + adjust_viewport_to_cursor(); - + setting_row=false; - - + + if (!cursor_changed_dirty) { - - if (is_inside_scene()) + if (is_inside_tree()) MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit"); cursor_changed_dirty=true; } - + } int TextEdit::cursor_get_column() const { - + return cursor.column; } int TextEdit::cursor_get_line() const { - + return cursor.line; } void TextEdit::_scroll_moved(double p_to_val) { - + if (updating_scrolls) return; - + if (h_scroll->is_visible()) cursor.x_ofs=h_scroll->get_val(); if (v_scroll->is_visible()) @@ -2203,87 +2457,87 @@ void TextEdit::_scroll_moved(double p_to_val) { int TextEdit::get_row_height() const { - + return cache.font->get_height()+cache.line_spacing; } int TextEdit::get_char_pos_for(int p_px,String p_str) const { - + int px=0; int c=0; - + int tab_w = cache.font->get_char_size(' ').width*tab_size; - + while (c<p_str.length()) { - + int w=0; - + if (p_str[c]=='\t') { - + int left = px%tab_w; if (left==0) w=tab_w; else w=tab_w-px%tab_w; // is right... - + } else { - + w=cache.font->get_char_size(p_str[c],p_str[c+1]).width; } - + if (p_px<(px+w/2)) break; px+=w; c++; } - + return c; } int TextEdit::get_column_x_offset(int p_char,String p_str) { - + int px=0; - + int tab_w = cache.font->get_char_size(' ').width*tab_size; - + for (int i=0;i<p_char;i++) { - + if (i>=p_str.length()) break; - + if (p_str[i]=='\t') { - + int left = px%tab_w; if (left==0) px+=tab_w; else px+=tab_w-px%tab_w; // is right... - + } else { px+=cache.font->get_char_size(p_str[i],p_str[i+1]).width; } } - + return px; - + } void TextEdit::insert_text_at_cursor(const String& p_text) { - + if (selection.active) { - + cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); - + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); selection.active=false; selection.selecting_mode=Selection::MODE_NONE; - + } - + _insert_text_at_cursor(p_text); update(); - + } Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const { @@ -2295,11 +2549,11 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2& p_pos) const { void TextEdit::set_text(String p_text){ - + setting_text=true; _clear(); _insert_text_at_cursor(p_text); - + cursor.column=0; cursor.line=0; cursor.x_ofs=0; @@ -2309,7 +2563,7 @@ void TextEdit::set_text(String p_text){ cursor_set_column(0); update(); setting_text=false; - + //get_range()->set(0); }; @@ -2317,29 +2571,53 @@ String TextEdit::get_text() { String longthing; int len = text.size(); for (int i=0;i<len;i++) { - - + + longthing+=text[i]; if (i!=len-1) longthing+="\n"; } - + return longthing; + +}; +String TextEdit::get_text_for_completion() { + + String longthing; + int len = text.size(); + for (int i=0;i<len;i++) { + + if (i==cursor.line) { + longthing+=text[i].substr(0,cursor.column); + longthing+=String::chr(0xFFFF); //not unicode, represents the cursor + longthing+=text[i].substr(cursor.column,text[i].size()); + } else { + + longthing+=text[i]; + } + + + if (i!=len-1) + longthing+="\n"; + } + + return longthing; + }; String TextEdit::get_line(int line) const { - + if (line<0 || line>=text.size()) return ""; - + return text[line]; - + }; void TextEdit::_clear() { - + clear_undo_history(); text.clear(); cursor.column=0; @@ -2352,31 +2630,31 @@ void TextEdit::_clear() { void TextEdit::clear() { - + setting_text=true; _clear(); setting_text=false; - + }; void TextEdit::set_readonly(bool p_readonly) { - - + + readonly=p_readonly; } void TextEdit::set_wrap(bool p_wrap) { - + wrap=p_wrap; } void TextEdit::set_max_chars(int p_max_chars) { - + max_chars=p_max_chars; } void TextEdit::_update_caches() { - + cache.style_normal=get_stylebox("normal"); cache.style_focus=get_stylebox("focus"); cache.font=get_font("font"); @@ -2387,16 +2665,17 @@ void TextEdit::_update_caches() { cache.mark_color=get_color("mark_color"); cache.current_line_color=get_color("current_line_color"); cache.breakpoint_color=get_color("breakpoint_color"); + cache.brace_mismatch_color=get_color("brace_mismatch_color"); cache.line_spacing=get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon=get_icon("tab"); text.set_font(cache.font); - + } void TextEdit::clear_colors() { - + keywords.clear(); color_regions.clear();; text.clear_caches(); @@ -2404,20 +2683,20 @@ void TextEdit::clear_colors() { } void TextEdit::set_custom_bg_color(const Color& p_color) { - + custom_bg_color=p_color; update(); } void TextEdit::add_keyword_color(const String& p_keyword,const Color& p_color) { - + keywords[p_keyword]=p_color; update(); - + } void TextEdit::add_color_region(const String& p_begin_key,const String& p_end_key,const Color &p_color,bool p_line_only) { - + color_regions.push_back(ColorRegion(p_begin_key,p_end_key,p_color,p_line_only)); text.clear_caches(); update(); @@ -2425,70 +2704,70 @@ void TextEdit::add_color_region(const String& p_begin_key,const String& p_end_ke } void TextEdit::set_symbol_color(const Color& p_color) { - + symbol_color=p_color; update(); } void TextEdit::set_syntax_coloring(bool p_enabled) { - + syntax_coloring=p_enabled; update(); } bool TextEdit::is_syntax_coloring_enabled() const { - + return syntax_coloring; } void TextEdit::cut() { - + if (!selection.active) return; - + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); OS::get_singleton()->set_clipboard(clipboard); - + cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); - + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); selection.active=false; selection.selecting_mode=Selection::MODE_NONE; update(); - + } void TextEdit::copy() { - + if (!selection.active) return; - + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); OS::get_singleton()->set_clipboard(clipboard); - + } void TextEdit::paste() { - + if (selection.active) { - + cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); - + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); selection.active=false; selection.selecting_mode=Selection::MODE_NONE; - + } - + String clipboard = OS::get_singleton()->get_clipboard(); _insert_text_at_cursor(clipboard); update(); - + } void TextEdit::select_all() { - + if (text.size()==1 && text[0].length()==0) return; selection.active=true; @@ -2498,95 +2777,95 @@ void TextEdit::select_all() { selection.to_column=text[selection.to_line].size(); selection.selecting_mode=Selection::MODE_NONE; update(); - + } void TextEdit::deselect() { - + selection.active=false; update(); } void TextEdit::select(int p_from_line,int p_from_column,int p_to_line,int p_to_column) { - + if (p_from_line>=text.size()) p_from_line=text.size()-1; if (p_from_column>=text[p_from_line].length()) p_from_column=text[p_from_line].length(); - + if (p_to_line>=text.size()) p_to_line=text.size()-1; if (p_to_column>=text[p_to_line].length()) p_to_column=text[p_to_line].length(); - + selection.from_line=p_from_line; selection.from_column=p_from_column; selection.to_line=p_to_line; selection.to_column=p_to_column; - + selection.active=true; - + if (selection.from_line==selection.to_line) { - + if (selection.from_column==selection.to_column) { - + selection.active=false; - + } else if (selection.from_column>selection.to_column) { - + SWAP( selection.from_column, selection.to_column ); } } else if (selection.from_line>selection.to_line) { - + SWAP( selection.from_line, selection.to_line ); SWAP( selection.from_column, selection.to_column ); } - - + + update(); } bool TextEdit::is_selection_active() const { - + return selection.active; } int TextEdit::get_selection_from_line() const { - + ERR_FAIL_COND_V(!selection.active,-1); return selection.from_line; - + } int TextEdit::get_selection_from_column() const { - + ERR_FAIL_COND_V(!selection.active,-1); return selection.from_column; - + } int TextEdit::get_selection_to_line() const { - + ERR_FAIL_COND_V(!selection.active,-1); return selection.to_line; - + } int TextEdit::get_selection_to_column() const { - + ERR_FAIL_COND_V(!selection.active,-1); return selection.to_column; - + } String TextEdit::get_selection_text() const { - + if (!selection.active) return ""; - + return _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - + } String TextEdit::get_word_under_cursor() const { - + int prev_cc = cursor.column; while(prev_cc >0) { bool is_char = _is_text_char(text[cursor.line][prev_cc-1]); @@ -2594,7 +2873,7 @@ String TextEdit::get_word_under_cursor() const { break; --prev_cc; } - + int next_cc = cursor.column; while(next_cc<text[cursor.line].length()) { bool is_char = _is_text_char(text[cursor.line][next_cc]); @@ -2608,7 +2887,7 @@ String TextEdit::get_word_under_cursor() const { } DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const { - + int col,line; if (search(p_key,p_search_flags,p_from_line,p_from_column,col,line)) { DVector<int> result; @@ -2616,46 +2895,46 @@ DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, result.set(0,line); result.set(1,col); return result; - + } else { - + return DVector<int>(); } } bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_line, int p_from_column,int &r_line,int &r_column) const { - + if (p_key.length()==0) return false; ERR_FAIL_INDEX_V(p_from_line,text.size(),false); ERR_FAIL_INDEX_V(p_from_column,text[p_from_line].length()+1,false); - + //search through the whole documment, but start by current line - + int line=-1; int pos=-1; - + line=p_from_line; - + for(int i=0;i<text.size()+1;i++) { //backwards is broken... //int idx=(p_search_flags&SEARCH_BACKWARDS)?(text.size()-i):i; //do backwards seearch - - + + if (line<0) { line=text.size()-1; } if (line==text.size()) { line=0; } - + String text_line = text[line]; int from_column=0; if (line==p_from_line) { - + if (i==text.size()) { //wrapped - + if (p_search_flags&SEARCH_BACKWARDS) { text_line=text_line.substr(from_column,text_line.length()); from_column=text_line.length(); @@ -2663,13 +2942,13 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li text_line=text_line.substr(0,from_column); from_column=0; } - + } else { - + from_column=p_from_column; } - - + + } else { //text_line=text_line.substr(0,p_from_column); //wrap around for missing begining. if (p_search_flags&SEARCH_BACKWARDS) @@ -2677,17 +2956,17 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li else from_column=0; } - + pos=-1; - + if (!(p_search_flags&SEARCH_BACKWARDS)) { - + pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column); } else { - + pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column); } - + if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) { //validate for whole words if (pos>0 && _is_text_char(text_line[pos-1])) @@ -2695,66 +2974,66 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li else if (_is_text_char(text_line[pos+p_key.length()])) pos=-1; } - + if (pos!=-1) break; - + if (p_search_flags&SEARCH_BACKWARDS) line--; else line++; - + } - + if (pos==-1) { r_line=-1; r_column=-1; return false; } - + r_line=line; r_column=pos; - - + + return true; } void TextEdit::_cursor_changed_emit() { - + emit_signal("cursor_changed"); cursor_changed_dirty=false; } void TextEdit::_text_changed_emit() { - + emit_signal("text_changed"); text_changed_dirty=false; } void TextEdit::set_line_as_marked(int p_line,bool p_marked) { - + ERR_FAIL_INDEX(p_line,text.size()); text.set_marked(p_line,p_marked); update(); } bool TextEdit::is_line_set_as_breakpoint(int p_line) const { - + ERR_FAIL_INDEX_V(p_line,text.size(),false); return text.is_breakpoint(p_line); - + } void TextEdit::set_line_as_breakpoint(int p_line,bool p_breakpoint) { - - + + ERR_FAIL_INDEX(p_line,text.size()); text.set_breakpoint(p_line,p_breakpoint); update(); } void TextEdit::get_breakpoints(List<int> *p_breakpoints) const { - + for(int i=0;i<text.size();i++) { if (text.is_breakpoint(i)) p_breakpoints->push_back(i); @@ -2762,39 +3041,39 @@ void TextEdit::get_breakpoints(List<int> *p_breakpoints) const { } int TextEdit::get_line_count() const { - + return text.size(); } void TextEdit::_do_text_op(const TextOperation& p_op, bool p_reverse) { - + ERR_FAIL_COND(p_op.type==TextOperation::TYPE_NONE); - + bool insert = p_op.type==TextOperation::TYPE_INSERT; if (p_reverse) insert=!insert; - + if (insert) { - + int check_line; int check_column; _base_insert_text(p_op.from_line,p_op.from_column,p_op.text,check_line,check_column); ERR_FAIL_COND( check_line != p_op.to_line ); // BUG ERR_FAIL_COND( check_column != p_op.to_column ); // BUG } else { - + _base_remove_text(p_op.from_line,p_op.from_column,p_op.to_line,p_op.to_column); } - + } void TextEdit::_clear_redo() { - + if (undo_stack_pos==NULL) return; //nothing to clear - + _push_current_op(); - + while (undo_stack_pos) { List<TextOperation>::Element *elem = undo_stack_pos; undo_stack_pos=undo_stack_pos->next(); @@ -2806,19 +3085,19 @@ void TextEdit::_clear_redo() { void TextEdit::undo() { _push_current_op(); - + if (undo_stack_pos==NULL) { - + if (!undo_stack.size()) return; //nothing to undo - + undo_stack_pos=undo_stack.back(); - + } else if (undo_stack_pos==undo_stack.front()) return; // at the bottom of the undo stack else undo_stack_pos=undo_stack_pos->prev(); - + _do_text_op( undo_stack_pos->get(),true); if(undo_stack_pos->get().chain_backward) { do { @@ -2826,19 +3105,19 @@ void TextEdit::undo() { _do_text_op(undo_stack_pos->get(), true); } while(!undo_stack_pos->get().chain_forward); } - + cursor_set_line(undo_stack_pos->get().from_line); cursor_set_column(undo_stack_pos->get().from_column); update(); } void TextEdit::redo() { - + _push_current_op(); - + if (undo_stack_pos==NULL) return; //nothing to do. - + _do_text_op(undo_stack_pos->get(), false); if(undo_stack_pos->get().chain_forward) { do { @@ -2853,12 +3132,12 @@ void TextEdit::redo() { } void TextEdit::clear_undo_history() { - + saved_version=0; current_op.type=TextOperation::TYPE_NONE; undo_stack_pos=NULL; undo_stack.clear(); - + } void TextEdit::_begin_compex_operation() { @@ -2897,12 +3176,12 @@ void TextEdit::_push_current_op() { } void TextEdit::set_draw_tabs(bool p_draw) { - + draw_tabs=p_draw; } bool TextEdit::is_drawing_tabs() const{ - + return draw_tabs; } @@ -2910,35 +3189,35 @@ uint32_t TextEdit::get_version() const { return current_op.version; } uint32_t TextEdit::get_saved_version() const { - + return saved_version; } void TextEdit::tag_saved_version() { - + saved_version=get_version(); } int TextEdit::get_v_scroll() const { - + return v_scroll->get_val(); } void TextEdit::set_v_scroll(int p_scroll) { - + v_scroll->set_val(p_scroll); cursor.line_ofs=p_scroll; } int TextEdit::get_h_scroll() const { - + return h_scroll->get_val(); } void TextEdit::set_h_scroll(int p_scroll) { - + h_scroll->set_val(p_scroll); } void TextEdit::set_completion(bool p_enabled,const Vector<String>& p_prefixes) { - + completion_prefixes.clear(); completion_enabled=p_enabled; for(int i=0;i<p_prefixes.size();i++) @@ -2946,7 +3225,7 @@ void TextEdit::set_completion(bool p_enabled,const Vector<String>& p_prefixes) { } void TextEdit::_confirm_completion() { - + String remaining=completion_current.substr(completion_base.length(),completion_current.length()-completion_base.length()); String l = text[cursor.line]; bool same=true; @@ -2958,44 +3237,89 @@ void TextEdit::_confirm_completion() { break; } } - + if (same) cursor_set_column(cursor.column+remaining.length()); - else + else { insert_text_at_cursor(remaining); - + if (remaining.ends_with("(") && auto_brace_completion_enabled) { + insert_text_at_cursor(")"); + cursor.column--; + } + } + _cancel_completion(); } -void TextEdit::_cancel_completion() { +void TextEdit::_cancel_code_hint() { + completion_hint=""; + update(); +} + +void TextEdit::_cancel_completion() { + if (!completion_active) return; - + completion_active=false; update(); + +} +static bool _is_completable(CharType c) { + + return !_is_symbol(c) || c=='"' || c=='\''; } -void TextEdit::_update_completion_candidates() { +void TextEdit::_update_completion_candidates() { + String l = text[cursor.line]; int cofs = CLAMP(cursor.column,0,l.length()); - + + String s; - while(cofs>0 && l[cofs-1]>32 && !_is_symbol(l[cofs-1])) { - s=String::chr(l[cofs-1])+s; - cofs--; + + //look for keywords first + + bool pre_keyword=false; + + if (cofs>0 && l[cofs-1]==' ') { + int kofs=cofs-1; + String kw; + while (kofs>=0 && l[kofs]==' ') + kofs--; + + while(kofs>=0 && l[kofs]>32 && _is_completable(l[kofs])) { + kw=String::chr(l[kofs])+kw; + kofs--; + } + + pre_keyword=keywords.has(kw); + print_line("KW "+kw+"? "+itos(pre_keyword)); + + } else { + + + while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) { + s=String::chr(l[cofs-1])+s; + if (l[cofs-1]=='\'' || l[cofs-1]=='"') + break; + + cofs--; + } } + update(); - - if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { + + if (!pre_keyword && s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) { //none to complete, cancel _cancel_completion(); return; } - + completion_options.clear(); completion_index=0; completion_base=s; @@ -3008,7 +3332,7 @@ void TextEdit::_update_completion_candidates() { if (max<ci_match) continue; for(int j=0;j<max;j++) { - + if (j>=completion_strings[i].length()) break; if (completion_current[j]!=completion_strings[i][j]) @@ -3019,181 +3343,180 @@ void TextEdit::_update_completion_candidates() { ci_match=m; completion_index=completion_options.size()-1; } - + } } - - - + + + if (completion_options.size()==0) { //no options to complete, cancel _cancel_completion(); return; - + } - + completion_current=completion_options[completion_index]; - + #if 0 // even there's only one option, user still get the chance to choose using it or not if (completion_options.size()==1) { //one option to complete, just complete it automagically _confirm_completion(); -// insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length())); + // insert_text_at_cursor(completion_options[0].substr(s.length(),completion_options[0].length()-s.length())); _cancel_completion(); return; - + } #endif if (completion_options.size()==1 && s==completion_options[0]) _cancel_completion(); - + completion_enabled=true; +} -} - void TextEdit::query_code_comple() { - + String l = text[cursor.line]; int ofs = CLAMP(cursor.column,0,l.length()); - String cs; - while(ofs>0 && l[ofs-1]>32) { - - if (_is_symbol(l[ofs-1])) { - String s; - while(ofs>0 && l[ofs-1]>32 && _is_symbol(l[ofs-1])) { - s=String::chr(l[ofs-1])+s; - ofs--; - } - if (completion_prefixes.has(s)) - cs=s+cs; - else - break; - } else { - - cs=String::chr(l[ofs-1])+cs; - ofs--; - } - - } - - if (cs!="") { - emit_signal("request_completion",cs,cursor.line); + + if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1])))) + emit_signal("request_completion"); + +} - } +void TextEdit::set_code_hint(const String& p_hint) { + + completion_hint=p_hint; + completion_hint_offset=-0xFFFF; + update(); } void TextEdit::code_complete(const Vector<String> &p_strings) { - - + + completion_strings=p_strings; completion_active=true; completion_current=""; completion_index=0; _update_completion_candidates(); -// + // } String TextEdit::get_tooltip(const Point2& p_pos) const { - + if (!tooltip_obj) return Control::get_tooltip(p_pos); int row,col; if (!_get_mouse_pos(p_pos, row,col)) { return Control::get_tooltip(p_pos); } - + String s = text[row]; if (s.length()==0) return Control::get_tooltip(p_pos); int beg=CLAMP(col,0,s.length()); int end=beg; - - + + if (s[beg]>32 || beg==s.length()) { - + bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - + while(beg>0 && s[beg-1]>32 && (symbol==_is_symbol(s[beg-1]))) { beg--; } while(end<s.length() && s[end+1]>32 && (symbol==_is_symbol(s[end+1]))) { end++; } - + if (end<s.length()) end+=1; - + String tt = tooltip_obj->call(tooltip_func,s.substr(beg,end-beg),tooltip_ud); - + return tt; - + } - + return Control::get_tooltip(p_pos); - + } void TextEdit::set_tooltip_request_func(Object *p_obj, const StringName& p_function,const Variant& p_udata) { - + tooltip_obj=p_obj; tooltip_func=p_function; tooltip_ud=p_udata; } +void TextEdit::set_line(int line, String new_text) +{ + if (line < 0 || line > text.size()) + return; + _remove_text(line, 0, line, text[line].length()); + _insert_text(line, 0, new_text); +} -void TextEdit::set_show_line_numbers(bool p_show) { +void TextEdit::insert_at(const String &p_text, int at) +{ + cursor_set_column(0); + cursor_set_line(at); + _insert_text(at, 0, p_text+"\n"); +} +void TextEdit::set_show_line_numbers(bool p_show) { + line_numbers=p_show; update(); } void TextEdit::_bind_methods() { - - + + ObjectTypeDB::bind_method(_MD("_input_event"),&TextEdit::_input_event); ObjectTypeDB::bind_method(_MD("_scroll_moved"),&TextEdit::_scroll_moved); ObjectTypeDB::bind_method(_MD("_cursor_changed_emit"),&TextEdit::_cursor_changed_emit); ObjectTypeDB::bind_method(_MD("_text_changed_emit"),&TextEdit::_text_changed_emit); ObjectTypeDB::bind_method(_MD("_push_current_op"),&TextEdit::_push_current_op); - + BIND_CONSTANT( SEARCH_MATCH_CASE ); BIND_CONSTANT( SEARCH_WHOLE_WORDS ); BIND_CONSTANT( SEARCH_BACKWARDS ); - -/* - ObjectTypeDB::bind_method(_MD("delete_char"),&TextEdit::delete_char); - ObjectTypeDB::bind_method(_MD("delete_line"),&TextEdit::delete_line); + + /* + ObjectTypeDB::bind_method(_MD("delete_char"),&TextEdit::delete_char); + ObjectTypeDB::bind_method(_MD("delete_line"),&TextEdit::delete_line); */ - + ObjectTypeDB::bind_method(_MD("set_text","text"),&TextEdit::set_text); ObjectTypeDB::bind_method(_MD("insert_text_at_cursor","text"),&TextEdit::insert_text_at_cursor); - + ObjectTypeDB::bind_method(_MD("get_line_count"),&TextEdit::get_line_count); ObjectTypeDB::bind_method(_MD("get_text"),&TextEdit::get_text); ObjectTypeDB::bind_method(_MD("get_line"),&TextEdit::get_line); - + ObjectTypeDB::bind_method(_MD("cursor_set_column","column"),&TextEdit::cursor_set_column); ObjectTypeDB::bind_method(_MD("cursor_set_line","line"),&TextEdit::cursor_set_line); - + ObjectTypeDB::bind_method(_MD("cursor_get_column"),&TextEdit::cursor_get_column); ObjectTypeDB::bind_method(_MD("cursor_get_line"),&TextEdit::cursor_get_line); - - + + ObjectTypeDB::bind_method(_MD("set_readonly","enable"),&TextEdit::set_readonly); ObjectTypeDB::bind_method(_MD("set_wrap","enable"),&TextEdit::set_wrap); ObjectTypeDB::bind_method(_MD("set_max_chars","amount"),&TextEdit::set_max_chars); - + ObjectTypeDB::bind_method(_MD("cut"),&TextEdit::cut); ObjectTypeDB::bind_method(_MD("copy"),&TextEdit::copy); ObjectTypeDB::bind_method(_MD("paste"),&TextEdit::paste); ObjectTypeDB::bind_method(_MD("select_all"),&TextEdit::select_all); ObjectTypeDB::bind_method(_MD("select","from_line","from_column","to_line","to_column"),&TextEdit::select); - + ObjectTypeDB::bind_method(_MD("is_selection_active"),&TextEdit::is_selection_active); ObjectTypeDB::bind_method(_MD("get_selection_from_line"),&TextEdit::get_selection_from_line); ObjectTypeDB::bind_method(_MD("get_selection_from_column"),&TextEdit::get_selection_from_column); @@ -3202,30 +3525,30 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text); ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor); ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind); - + ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo); ObjectTypeDB::bind_method(_MD("redo"),&TextEdit::redo); ObjectTypeDB::bind_method(_MD("clear_undo_history"),&TextEdit::clear_undo_history); ObjectTypeDB::bind_method(_MD("set_syntax_coloring","enable"),&TextEdit::set_syntax_coloring); ObjectTypeDB::bind_method(_MD("is_syntax_coloring_enabled"),&TextEdit::is_syntax_coloring_enabled); - + ObjectTypeDB::bind_method(_MD("add_keyword_color","keyword","color"),&TextEdit::add_keyword_color); ObjectTypeDB::bind_method(_MD("add_color_region","begin_key","end_key","color","line_only"),&TextEdit::add_color_region,DEFVAL(false)); ObjectTypeDB::bind_method(_MD("set_symbol_color","color"),&TextEdit::set_symbol_color); ObjectTypeDB::bind_method(_MD("set_custom_bg_color","color"),&TextEdit::set_custom_bg_color); ObjectTypeDB::bind_method(_MD("clear_colors"),&TextEdit::clear_colors); - - + + ADD_SIGNAL(MethodInfo("cursor_changed")); ADD_SIGNAL(MethodInfo("text_changed")); - ADD_SIGNAL(MethodInfo("request_completion",PropertyInfo(Variant::STRING,"keyword"),PropertyInfo(Variant::INT,"line"))); - + ADD_SIGNAL(MethodInfo("request_completion")); + } TextEdit::TextEdit() { - + readonly=false; setting_row=false; draw_tabs=false; @@ -3238,39 +3561,39 @@ TextEdit::TextEdit() { tab_size=4; text.set_tab_size(tab_size); text.clear(); -// text.insert(1,"Mongolia.."); -// text.insert(2,"PAIS GENEROSO!!"); + // text.insert(1,"Mongolia.."); + // text.insert(2,"PAIS GENEROSO!!"); text.set_color_regions(&color_regions); - + h_scroll = memnew( HScrollBar ); v_scroll = memnew( VScrollBar ); - + add_child(h_scroll); add_child(v_scroll); - + updating_scrolls=false; selection.active=false; - + h_scroll->connect("value_changed", this,"_scroll_moved"); v_scroll->connect("value_changed", this,"_scroll_moved"); - + cursor_changed_dirty=false; text_changed_dirty=false; - + selection.selecting_mode=Selection::MODE_NONE; selection.selecting_line=0; selection.selecting_column=0; selection.selecting_test=false; selection.active=false; syntax_coloring=false; - + custom_bg_color=Color(0,0,0,0); idle_detect = memnew( Timer ); add_child(idle_detect); idle_detect->set_one_shot(true); idle_detect->set_wait_time(GLOBAL_DEF("display/text_edit_idle_detect_sec",3)); idle_detect->connect("timeout", this,"_push_current_op"); - + #if 0 syntax_coloring=true; keywords["void"]=Color(0.3,0.0,0.1); @@ -3280,24 +3603,24 @@ TextEdit::TextEdit() { keywords["extends"]=Color(0.3,0.0,0.1); keywords["constructor"]=Color(0.3,0.0,0.1); symbol_color=Color(0.1,0.0,0.3,1.0); - + color_regions.push_back(ColorRegion("/*","*/",Color(0.4,0.6,0,4))); color_regions.push_back(ColorRegion("//","",Color(0.6,0.6,0.4))); color_regions.push_back(ColorRegion("\"","\"",Color(0.4,0.7,0.7))); color_regions.push_back(ColorRegion("'","'",Color(0.4,0.8,0.8))); color_regions.push_back(ColorRegion("#","",Color(0.2,1.0,0.2))); - + #endif - + current_op.type=TextOperation::TYPE_NONE; undo_enabled=true; - undo_stack_pos=NULL; + undo_stack_pos=NULL; setting_text=false; last_dblclk=0; current_op.version=0; version=0; saved_version=0; - + completion_enabled=false; completion_active=false; completion_line_ofs=0; @@ -3305,9 +3628,10 @@ TextEdit::TextEdit() { line_numbers=false; next_operation_is_complex=false; auto_brace_completion_enabled=false; + brace_matching_enabled=false; + } -TextEdit::~TextEdit(){ +TextEdit::~TextEdit() +{ } - - diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 15c289a87e..1d57aef416 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -63,6 +63,7 @@ class TextEdit : public Control { int from_line,from_column; int to_line,to_column; + bool shiftclick_left; } selection; @@ -79,6 +80,7 @@ class TextEdit : public Control { Color mark_color; Color breakpoint_color; Color current_line_color; + Color brace_mismatch_color; int row_height; int line_spacing; @@ -138,7 +140,7 @@ class TextEdit : public Control { int size() const { return text.size(); } void clear(); void clear_caches(); - _FORCE_INLINE_ const String& operator[](int p_line) const { return text[p_line].data; } + _FORCE_INLINE_ const String& operator[](int p_line) const { return text[p_line].data; } Text() { tab_size=4; } }; @@ -185,6 +187,8 @@ class TextEdit : public Control { int completion_index; Rect2i completion_rect; int completion_line_ofs; + String completion_hint; + int completion_hint_offset; bool setting_text; @@ -208,6 +212,7 @@ class TextEdit : public Control { bool line_numbers; bool auto_brace_completion_enabled; + bool brace_matching_enabled; bool cut_copy_line; uint64_t last_dblclk; @@ -261,6 +266,7 @@ class TextEdit : public Control { void _clear(); void _cancel_completion(); + void _cancel_code_hint(); void _confirm_completion(); void _update_completion_candidates(); @@ -299,6 +305,7 @@ public: void set_text(String p_text); void insert_text_at_cursor(const String& p_text); + void insert_at(const String& p_text, int at); int get_line_count() const; void set_line_as_marked(int p_line,bool p_marked); void set_line_as_breakpoint(int p_line,bool p_breakpoint); @@ -306,12 +313,17 @@ public: void get_breakpoints(List<int> *p_breakpoints) const; String get_text(); String get_line(int line) const; + void set_line(int line, String new_text); void backspace_at_cursor(); inline void set_auto_brace_completion(bool p_enabled) { auto_brace_completion_enabled = p_enabled; } - + inline void set_brace_matching(bool p_enabled) { + brace_matching_enabled=p_enabled; + update(); + } + void cursor_set_column(int p_col); void cursor_set_line(int p_row); @@ -348,7 +360,7 @@ public: void undo(); void redo(); - void clear_undo_history(); + void clear_undo_history(); void set_draw_tabs(bool p_draw); @@ -374,10 +386,13 @@ public: void set_tooltip_request_func(Object *p_obj, const StringName& p_function, const Variant& p_udata); - void set_completion(bool p_enabled,const Vector<String>& p_prefixes); + void set_completion(bool p_enabled,const Vector<String>& p_prefixes); void code_complete(const Vector<String> &p_strings); + void set_code_hint(const String& p_hint); void query_code_comple(); + String get_text_for_completion(); + TextEdit(); ~TextEdit(); }; diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp index 7954ac65df..1a7087b7ef 100644 --- a/scene/gui/texture_button.cpp +++ b/scene/gui/texture_button.cpp @@ -31,28 +31,37 @@ Size2 TextureButton::get_minimum_size() const { + Size2 rscale; if (normal.is_null()) { if (pressed.is_null()) { if (hover.is_null()) if (click_mask.is_null()) - return Size2(); + rscale= Size2(); else - return click_mask->get_size(); + rscale= click_mask->get_size(); else - return hover->get_size(); + rscale= hover->get_size(); } else - return pressed->get_size(); + rscale= pressed->get_size()*scale; } else - return normal->get_size(); + rscale= normal->get_size(); + + return rscale*scale; } bool TextureButton::has_point(const Point2& p_point) const { + if (scale[0] <= 0 || scale[1] <= 0) { + return false; + } + + Point2 ppos = p_point/scale; + if (click_mask.is_valid()) { - Point2i p =p_point; + Point2i p =ppos; if (p.x<0 || p.x>=click_mask->get_size().width || p.y<0 || p.y>=click_mask->get_size().height) return false; @@ -71,46 +80,57 @@ void TextureButton::_notification(int p_what) { DrawMode draw_mode = get_draw_mode(); // if (normal.is_null()) // break; + + Ref<Texture> texdraw; + switch (draw_mode) { case DRAW_NORMAL: { if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } break; case DRAW_PRESSED: { if (pressed.is_null()) { if (hover.is_null()) { if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } else - hover->draw(canvas_item,Point2()); + texdraw=hover; } else - pressed->draw(canvas_item,Point2()); + texdraw=pressed; } break; case DRAW_HOVER: { if (hover.is_null()) { if (pressed.is_valid() && is_pressed()) - pressed->draw(canvas_item,Point2()); + texdraw=pressed; else if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } else - hover->draw(canvas_item,Point2()); + texdraw=hover; } break; case DRAW_DISABLED: { if (disabled.is_null()) { if (normal.is_valid()) - normal->draw(canvas_item,Point2()); + texdraw=normal; } else - disabled->draw(canvas_item,Point2()); + texdraw=disabled; } break; } + + if (texdraw.is_valid()) { + Rect2 drect(Point2(),texdraw->get_size()*scale); + draw_texture_rect(texdraw,drect,false,modulate); + + } if (has_focus() && focused.is_valid()) { - focused->draw(canvas_item, Point2()); + Rect2 drect(Point2(),focused->get_size()*scale); + draw_texture_rect(focused,drect,false,modulate); + }; } break; @@ -125,6 +145,8 @@ void TextureButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_disabled_texture","texture:Texture"),&TextureButton::set_disabled_texture); ObjectTypeDB::bind_method(_MD("set_focused_texture","texture:Texture"),&TextureButton::set_focused_texture); ObjectTypeDB::bind_method(_MD("set_click_mask","mask:BitMap"),&TextureButton::set_click_mask); + ObjectTypeDB::bind_method(_MD("set_scale","scale"),&TextureButton::set_scale); + ObjectTypeDB::bind_method(_MD("set_modulate","color"),&TextureButton::set_modulate); ObjectTypeDB::bind_method(_MD("get_normal_texture:Texture"),&TextureButton::get_normal_texture); ObjectTypeDB::bind_method(_MD("get_pressed_texture:Texture"),&TextureButton::get_pressed_texture); @@ -132,6 +154,8 @@ void TextureButton::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_disabled_texture:Texture"),&TextureButton::get_disabled_texture); ObjectTypeDB::bind_method(_MD("get_focused_texture:Texture"),&TextureButton::get_focused_texture); ObjectTypeDB::bind_method(_MD("get_click_mask:BitMap"),&TextureButton::get_click_mask); + 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")); @@ -139,6 +163,8 @@ void TextureButton::_bind_methods() { 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")); } @@ -206,6 +232,29 @@ void TextureButton::set_focused_texture(const Ref<Texture>& p_focused) { focused = p_focused; }; +void TextureButton::set_scale(Size2 p_scale) { + + scale=p_scale; + minimum_size_changed(); + update(); +} + +Size2 TextureButton::get_scale() const{ + + return scale; +} + +void TextureButton::set_modulate(const Color& p_modulate) { + modulate=p_modulate; + update(); +} + +Color TextureButton::get_modulate() const { + return modulate; +} + TextureButton::TextureButton() { + scale=Size2(1.0, 1.0); + modulate=Color(1,1,1); } diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h index d186966cb1..94bc53b3ff 100644 --- a/scene/gui/texture_button.h +++ b/scene/gui/texture_button.h @@ -41,6 +41,8 @@ class TextureButton : public BaseButton { Ref<Texture> disabled; Ref<Texture> focused; Ref<BitMap> click_mask; + Size2 scale; + Color modulate; protected: @@ -66,6 +68,11 @@ public: Ref<Texture> get_focused_texture() const; Ref<BitMap> get_click_mask() const; + void set_scale(Size2 p_scale); + Size2 get_scale() const; + + void set_modulate(const Color& p_modulate); + Color get_modulate() const; TextureButton(); }; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 9084983a4c..b7b52a39dc 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -1438,8 +1438,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ if (p_button==BUTTON_LEFT) { /* process selection */ - if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON)) { - + if (p_doubleclick && (!c.editable || c.mode==TreeItem::CELL_MODE_CUSTOM || c.mode==TreeItem::CELL_MODE_ICON || c.mode==TreeItem::CELL_MODE_CHECK)) { emit_signal("item_activated"); return -1; @@ -1500,7 +1499,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ case TreeItem::CELL_MODE_STRING: { //nothing in particular - if (select_mode==SELECT_MULTI && (get_scene()->get_last_event_id() == focus_in_id || !already_cursor)) { + if (select_mode==SELECT_MULTI && (get_tree()->get_last_event_id() == focus_in_id || !already_cursor)) { bring_up_editor=false; } @@ -1576,7 +1575,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos,int x_ofs,int y_ofs,bool p_ editor_text=String::num( p_item->cells[col].val, Math::decimals( p_item->cells[col].step ) ); bring_up_value_editor=false; - if (select_mode==SELECT_MULTI && get_scene()->get_last_event_id() == focus_in_id) + if (select_mode==SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id) bring_up_editor=false; } @@ -1694,6 +1693,13 @@ void Tree::text_editor_enter(String p_text) { case TreeItem::CELL_MODE_RANGE: { c.val=p_text.to_double(); + if (c.step>0) + c.val=Math::stepify(c.val,c.step); + if (c.val<c.min) + c.val=c.min; + else if (c.val>c.max) + c.val=c.max; + //popup_edited_item->edited_signal.call( popup_edited_item_col ); } break; default: { ERR_FAIL(); } @@ -2344,7 +2350,7 @@ void Tree::_notification(int p_what) { if (p_what==NOTIFICATION_FOCUS_ENTER) { - focus_in_id=get_scene()->get_last_event_id(); + focus_in_id=get_tree()->get_last_event_id(); } if (p_what==NOTIFICATION_MOUSE_EXIT) { @@ -2354,7 +2360,7 @@ void Tree::_notification(int p_what) { } } - if (p_what==NOTIFICATION_ENTER_SCENE) { + if (p_what==NOTIFICATION_ENTER_TREE) { update_cache();; } @@ -2812,7 +2818,7 @@ int Tree::get_item_offset(TreeItem *p_item) const { void Tree::ensure_cursor_is_visible() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; TreeItem *selected = get_selected(); diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp index 9a1c070529..050fd890f4 100644 --- a/scene/gui/video_player.cpp +++ b/scene/gui/video_player.cpp @@ -32,10 +32,10 @@ void VideoPlayer::_notification(int p_notification) { switch (p_notification) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { //set_idle_process(false); //don't annoy - if (stream.is_valid() && autoplay && !get_scene()->is_editor_hint()) + if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint()) play(); } break; @@ -45,20 +45,15 @@ void VideoPlayer::_notification(int p_notification) { return; if (paused) return; + if (!stream->is_playing()) + return; - stream->update(get_scene()->get_idle_process_time()); - while (stream->get_pending_frame_count()) { - - Image img = stream->pop_frame(); - if (texture->get_width() == 0) { - texture->create(img.get_width(),img.get_height(),img.get_format(),Texture::FLAG_VIDEO_SURFACE|Texture::FLAG_FILTER); - update(); - minimum_size_changed(); - } else { - - if (stream->get_pending_frame_count() == 0) - texture->set_data(img); - }; + stream->update(get_tree()->get_idle_process_time()); + int prev_width = texture->get_width(); + stream->pop_frame(texture); + if (prev_width == 0) { + update(); + minimum_size_changed(); }; } break; @@ -123,7 +118,7 @@ Ref<VideoStream> VideoPlayer::get_stream() const { void VideoPlayer::play() { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); if (stream.is_null()) return; stream->play(); @@ -132,7 +127,7 @@ void VideoPlayer::play() { void VideoPlayer::stop() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (stream.is_null()) return; @@ -197,7 +192,7 @@ String VideoPlayer::get_stream_name() const { return stream->get_name(); }; -float VideoPlayer::get_pos() const { +float VideoPlayer::get_stream_pos() const { if (stream.is_null()) return 0; @@ -236,7 +231,7 @@ void VideoPlayer::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_stream_name"),&VideoPlayer::get_stream_name); - ObjectTypeDB::bind_method(_MD("get_pos"),&VideoPlayer::get_pos); + ObjectTypeDB::bind_method(_MD("get_stream_pos"),&VideoPlayer::get_stream_pos); ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&VideoPlayer::set_autoplay); ObjectTypeDB::bind_method(_MD("has_autoplay"),&VideoPlayer::has_autoplay); @@ -257,9 +252,9 @@ void VideoPlayer::_bind_methods() { VideoPlayer::VideoPlayer() { volume=1; - loops=false; - paused=false; - autoplay=false; + loops = false; + paused = false; + autoplay = false; expand = true; loops = false; }; diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h index db5f9a58a6..3eb629ced5 100644 --- a/scene/gui/video_player.h +++ b/scene/gui/video_player.h @@ -77,7 +77,7 @@ public: float get_volume_db() const; String get_stream_name() const; - float get_pos() const; + float get_stream_pos() const; void set_autoplay(bool p_vol); bool has_autoplay() const; diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index b0fcf9717b..16c2ec9706 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -131,14 +131,55 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina uint32_t flags=0; - if (bool(GLOBAL_DEF("image_loader/filter",true))) + + FileAccess *f2 = FileAccess::open(p_path+".flags",FileAccess::READ); + Map<String,bool> flags_found; + if (f2) { + + while(!f2->eof_reached()) { + String l2 = f2->get_line(); + int eqpos = l2.find("="); + if (eqpos!=-1) { + String flag=l2.substr(0,eqpos).strip_edges(); + String val=l2.substr(eqpos+1,l2.length()).strip_edges().to_lower(); + flags_found[flag]=(val=="true" || val=="1")?true:false; + } + } + memdelete(f2); + } + + + if (flags_found.has("filter")) { + if (flags_found["filter"]) + flags|=Texture::FLAG_FILTER; + } else if (bool(GLOBAL_DEF("image_loader/filter",true))) { flags|=Texture::FLAG_FILTER; - if (bool(GLOBAL_DEF("image_loader/gen_mipmaps",true))) + } + + + if (flags_found.has("gen_mipmaps")) { + if (flags_found["gen_mipmaps"]) + flags|=Texture::FLAG_MIPMAPS; + } else if (bool(GLOBAL_DEF("image_loader/gen_mipmaps",true))) { flags|=Texture::FLAG_MIPMAPS; - if (bool(GLOBAL_DEF("image_loader/repeat",false))) + } + + if (flags_found.has("repeat")) { + if (flags_found["repeat"]) + flags|=Texture::FLAG_REPEAT; + } else if (bool(GLOBAL_DEF("image_loader/repeat",true))) { flags|=Texture::FLAG_REPEAT; + } + if (flags_found.has("anisotropic")) { + if (flags_found["anisotropic"]) + flags|=Texture::FLAG_ANISOTROPIC_FILTER; + } + if (flags_found.has("tolinear")) { + if (flags_found["tolinear"]) + flags|=Texture::FLAG_CONVERT_TO_LINEAR; + } if (debug_load_times) begtime=OS::get_singleton()->get_ticks_usec(); diff --git a/scene/io/scene_format_object.cpp b/scene/io/scene_format_object.cpp deleted file mode 100644 index 6ffae30282..0000000000 --- a/scene/io/scene_format_object.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/*************************************************************************/ -/* scene_format_object.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "scene_format_object.h" -#include "print_string.h" -#include "globals.h" -#include "scene/resources/packed_scene.h" -#include "io/resource_loader.h" - -#ifdef OLD_SCENE_FORMAT_ENABLED - -void SceneFormatSaverObject::save_node(const Node* p_root,const Node* p_node,const Node* p_owner,ObjectFormatSaver *p_saver,String p_base_path,uint32_t p_flags,Map<const Node*,uint32_t>& owner_id) const { - - if (p_node!=p_root && p_node->get_owner()==NULL) - return; - - - if (p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES || p_node->get_owner() == p_owner || p_node == p_owner ) { - - Dictionary d; - if (p_root!=p_node) { - d["path"]=p_root->get_path_to(p_node->get_parent()); - } - - d["name"]=p_node->get_name(); - - /* Connections */ - - List<MethodInfo> signal_list; - - p_node->get_signal_list(&signal_list); - - int conn_count=0; - - Set<Node::Connection> exclude_connections; - - if (!(p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES)) { - - Vector<Node::Connection> ex = p_node->get_instance_connections(); - for(int i=0;i<ex.size();i++) { - exclude_connections.insert(ex[i]); - } - } - - for (List<MethodInfo>::Element *S=signal_list.front();S;S=S->next()) { - - List<Node::Connection> connections; - p_node->get_signal_connection_list(S->get().name,&connections); - for(List<Node::Connection>::Element *E=connections.front();E;E=E->next()) { - - Node::Connection &c=E->get(); - if (!(c.flags&Object::CONNECT_PERSIST)) - continue; - if (exclude_connections.has(c)) - continue; - - Node *target = c.target->cast_to<Node>(); - if (!target) - continue; //connected to something not a node, ignoring - - Dictionary cd; - cd["signal"]=c.signal; - cd["target"]=p_node->get_path_to(target); - cd["method"]=c.method; - cd["realtime"]=!(c.flags&Object::CONNECT_DEFERRED); - if (c.binds.size()) - cd["binds"]=c.binds; - d["connection/"+itos(conn_count+1)]=cd; - - conn_count++; - } - } - - d["connection_count"]=conn_count; - if (owner_id.has(p_node->get_owner())) { - - d["owner"]=owner_id[p_node->get_owner()]; - } - - /* Groups */ - - DVector<String> group_array; - List<Node::GroupInfo> groups; - p_node->get_groups(&groups); - Set<StringName> exclude_groups; - - if (!(p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES)) { - //generate groups to exclude (came from instance) - Vector<StringName> eg; - eg=p_node->get_instance_groups(); - for(int i=0;i<eg.size();i++) - exclude_groups.insert(eg[i]); - } - - for(List<Node::GroupInfo>::Element*E=groups.front();E;E=E->next()) { - - if (E->get().persistent && !exclude_groups.has(E->get().name)) - group_array.push_back(E->get().name); - } - - if (group_array.size()) - d["groups"]=group_array; - - /* Save */ - - if (p_owner!=p_node && p_node->get_filename()!="") { - - String instance_path; - if (p_flags&SceneSaver::FLAG_RELATIVE_PATHS) - instance_path=p_base_path.path_to_file(Globals::get_singleton()->localize_path(p_node->get_filename())); - else - instance_path=p_node->get_filename(); - d["instance"]=instance_path; - - if (p_flags&SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES) { - - int id = owner_id.size(); - d["owner_id"]=id; - owner_id[p_node]=id; - - p_saver->save(p_node,d); - - //owner change! - for (int i=0;i<p_node->get_child_count();i++) { - - save_node(p_root,p_node->get_child(i),p_node,p_saver,p_base_path,p_flags,owner_id); - } - return; - - } else { - DVector<String> prop_names; - Array prop_values; - - List<PropertyInfo> properties; - p_node->get_property_list(&properties); - - //instance state makes sure that only changes to instance are saved - Dictionary instance_state=p_node->get_instance_state(); - - for(List<PropertyInfo>::Element *E=properties.front();E;E=E->next()) { - - if (!(E->get().usage&PROPERTY_USAGE_STORAGE)) - continue; - - String name=E->get().name; - Variant value=p_node->get(E->get().name); - - if (!instance_state.has(name)) - continue; // did not change since it was loaded, not save - if (value==instance_state[name]) - continue; - prop_names.push_back( name ); - prop_values.push_back( value ); - - } - - d["override_names"]=prop_names; - d["override_values"]=prop_values; - - p_saver->save(NULL,d); - } - } else { - - p_saver->save(p_node,d); - } - } - - for (int i=0;i<p_node->get_child_count();i++) { - - save_node(p_root,p_node->get_child(i),p_owner,p_saver,p_base_path,p_flags,owner_id); - } -} - - -Error SceneFormatSaverObject::save(const String &p_path,const Node* p_scene,uint32_t p_flags,const Ref<OptimizedSaver> &p_optimizer) { - - String extension=p_path.extension(); - if (extension=="scn") - extension="bin"; - if (extension=="xscn") - extension="xml"; - - String local_path=Globals::get_singleton()->localize_path(p_path); - uint32_t saver_flags=0; - if (p_flags&SceneSaver::FLAG_RELATIVE_PATHS) - saver_flags|=ObjectSaver::FLAG_RELATIVE_PATHS; - if (p_flags&SceneSaver::FLAG_BUNDLE_RESOURCES) - saver_flags|=ObjectSaver::FLAG_BUNDLE_RESOURCES; - if (p_flags&SceneSaver::FLAG_OMIT_EDITOR_PROPERTIES) - saver_flags|=ObjectSaver::FLAG_OMIT_EDITOR_PROPERTIES; - if (p_flags&SceneSaver::FLAG_SAVE_BIG_ENDIAN) - saver_flags|=ObjectSaver::FLAG_SAVE_BIG_ENDIAN; - - ObjectFormatSaver *saver = ObjectSaver::instance_format_saver(local_path,"SCENE",extension,saver_flags,p_optimizer); - - ERR_FAIL_COND_V(!saver,ERR_FILE_UNRECOGNIZED); - - /* SAVE SCENE */ - - Map<const Node*,uint32_t> node_id_map; - save_node(p_scene,p_scene,p_scene,saver,local_path,p_flags,node_id_map); - - memdelete(saver); - - return OK; -} - -void SceneFormatSaverObject::get_recognized_extensions(List<String> *p_extensions) const { - - p_extensions->push_back("xml"); - p_extensions->push_back("scn"); - p_extensions->push_back("xscn"); - -// ObjectSaver::get_recognized_extensions(p_extensions); -} - - -///////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////////// - -void SceneFormatLoaderObject::_apply_meta(Node *node, const Variant&meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map) { - - r_err = OK; - - - Dictionary d=meta; - - if (!d.has("name")) { - - r_err=ERR_WTF; - memdelete(node); - ERR_FAIL_COND(!d.has("name")); - } - - - node->set_name(d["name"]); - int connection_count=d.has("connection_count")?d["connection_count"].operator int():0; - - - for (int i=0;i<connection_count;i++) { - - Dictionary cd=d["connection/"+itos(i+1)]; - - ERR_CONTINUE(!cd.has("target")); - ERR_CONTINUE(!cd.has("method")); - ERR_CONTINUE(!cd.has("realtime")); - ERR_CONTINUE(!cd.has("signal")); - - ConnectionItem ci; - - ci.node=node; - ci.target=cd["target"]; - ci.method=cd["method"]; - ci.signal=cd["signal"]; - ci.realtime=cd["realtime"]; - if (cd.has("binds")) - ci.binds=cd["binds"]; - - connections.push_back(ci); - - } - - DVector<String> groups=d.has("groups")?d["groups"].operator DVector<String>():DVector<String>(); - for (int i=0;i<groups.size();i++) { - - node->add_to_group(groups[i],true); - } - -} - - - -Ref<SceneInteractiveLoader> SceneFormatLoaderObject::load_interactive(const String &p_path,bool p_save_root_state) { - - SceneInteractiveLoaderObject *sil = memnew( SceneInteractiveLoaderObject(p_path,p_save_root_state) ); - - if (sil->error!=OK) { - - memdelete( sil ); - return Ref<SceneInteractiveLoader>(); - } - - return Ref<SceneInteractiveLoader>( sil ); - -} - - -Node* SceneFormatLoaderObject::load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_save_instance_state,Map<uint32_t,Node*>& owner_map) { - - r_err = OK; - - Node *node=obj->cast_to<Node>(); - - _apply_meta(node,meta,p_loader,connections,r_err,owner_map); - if (r_err!=OK) - return NULL; - - Dictionary d=meta; - - if (p_root) { - NodePath path=d.has("path")?d["path"].operator NodePath():NodePath("."); - - Node *parent=p_root->get_node(path); - if (!parent) { - memdelete(node); - r_err=ERR_FILE_CORRUPT; - ERR_FAIL_COND_V(!parent,NULL); - } - - parent->add_child(node); - - if (d.has("owner_id")) { - //is owner - owner_map[d["owner_id"]]=node; - if (d.has("instance")) - node->set_filename(d["instance"]); - - } - - if (d.has("owner")) { - - uint32_t owner = d["owner"]; - ERR_FAIL_COND_V(!owner_map.has(owner),NULL); - node->set_owner(owner_map[owner]); - } else { - - node->set_owner(p_root); - } - } - - return node; -} - -void SceneFormatLoaderObject::_apply_connections(List<ConnectionItem>& connections) { - - int idx=0; - for (List<ConnectionItem>::Element *E=connections.front();E;E=E->next()) { - - ConnectionItem &ci=E->get(); - Node *target = ci.node->get_node(ci.target); - ERR_CONTINUE(!target); - ci.node->connect(ci.signal,target,ci.method,ci.binds,(ci.realtime?0:Object::CONNECT_DEFERRED)|Object::CONNECT_PERSIST); - idx++; - } - -} - -Node* SceneFormatLoaderObject::load(const String &p_path,bool p_save_instance_state) { - - List<ConnectionItem> connections; - - String extension=p_path.extension(); - if (extension=="scn") - extension="bin"; - if (extension=="xscn") - extension="xml"; - - String local_path = Globals::get_singleton()->localize_path(p_path); - - ObjectFormatLoader *loader = ObjectLoader::instance_format_loader(local_path,"SCENE",extension); - - ERR_EXPLAIN("Couldn't load scene: "+p_path); - ERR_FAIL_COND_V(!loader,NULL); - - Node *root=NULL; - Map<uint32_t,Node*> owner_map; - - while(true) { - - Object *obj=NULL; - Variant metav; - Error r_err=loader->load(&obj,metav); - - if (r_err == ERR_SKIP) { - continue; - }; - - if (r_err==ERR_FILE_EOF) { - memdelete(loader); - ERR_FAIL_COND_V(!root,NULL); - _apply_connections(connections); - return root; - } - - if (r_err || (!obj && metav.get_type()==Variant::NIL)) { - memdelete(loader); - ERR_EXPLAIN("Object Loader Failed for Scene: "+p_path) ; - ERR_FAIL_COND_V( r_err, NULL); - ERR_EXPLAIN("Object Loader Failed for Scene: "+p_path) ; - ERR_FAIL_COND_V( !obj && metav.get_type()==Variant::NIL,NULL); - } - - if (obj) { - if (obj->cast_to<Node>()) { - - Error err; - Node* node = load_node(obj, metav, root, loader,connections,err,p_save_instance_state,owner_map); - if (err) - memdelete(loader); - - ERR_FAIL_COND_V( err, NULL ); - if (!root) - root=node; - } else { - - memdelete(loader); - ERR_FAIL_V( NULL ); - - } - } else { - - // check for instance - Dictionary meta=metav; - if (meta.has("instance")) { - if (!root) { - - memdelete(loader); - ERR_FAIL_COND_V(!root,NULL); - } - - String path = meta["instance"]; - - if (path.find("://")==-1 && path.is_rel_path()) { - // path is relative to file being loaded, so convert to a resource path - path=Globals::get_singleton()->localize_path( - local_path.get_base_dir()+"/"+path); - } - - - Node *scene = SceneLoader::load(path); - - if (!scene) { - - Ref<PackedScene> sd = ResourceLoader::load(path); - if (sd.is_valid()) { - - scene=sd->instance(); - } - } - - - if (!scene) { - - memdelete(loader); - ERR_FAIL_COND_V(!scene,NULL); - } - - if (p_save_instance_state) - scene->generate_instance_state(); - - - Error err; - _apply_meta(scene,metav,loader,connections,err,owner_map); - if (err!=OK) { - memdelete(loader); - ERR_FAIL_COND_V(err!=OK,NULL); - } - - Node *parent=root; - - if (meta.has("path")) - parent=root->get_node(meta["path"]); - - - if (!parent) { - - memdelete(loader); - ERR_FAIL_COND_V(!parent,NULL); - } - - - if (meta.has("override_names") && meta.has("override_values")) { - - DVector<String> override_names=meta["override_names"]; - Array override_values=meta["override_values"]; - - int len = override_names.size(); - if ( len > 0 && len == override_values.size() ) { - - DVector<String>::Read names = override_names.read(); - - for(int i=0;i<len;i++) { - - scene->set(names[i],override_values[i]); - } - - } - - } - - scene->set_filename(path); - - parent->add_child(scene); - scene->set_owner(root); - } - } - } - - return NULL; -} - -void SceneFormatLoaderObject::get_recognized_extensions(List<String> *p_extensions) const { - - p_extensions->push_back("xml"); - p_extensions->push_back("scn"); - p_extensions->push_back("xscn"); - -// ObjectLoader::get_recognized_extensions(p_extensions); - -} - - - -/////////////////////////////////////////////////// - - -void SceneInteractiveLoaderObject::_apply_meta(Node *node, const Variant&meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map) { - - r_err = OK; - - - Dictionary d=meta; - - if (!d.has("name")) { - - r_err=ERR_WTF; - memdelete(node); - ERR_FAIL_COND(!d.has("name")); - } - - - node->set_name(d["name"]); - int connection_count=d.has("connection_count")?d["connection_count"].operator int():0; - - - for (int i=0;i<connection_count;i++) { - - Dictionary cd=d["connection/"+itos(i+1)]; - - ERR_CONTINUE(!cd.has("target")); - ERR_CONTINUE(!cd.has("method")); - ERR_CONTINUE(!cd.has("realtime")); - ERR_CONTINUE(!cd.has("signal")); - - ConnectionItem ci; - - ci.node=node; - ci.target=cd["target"]; - ci.method=cd["method"]; - ci.signal=cd["signal"]; - ci.realtime=cd["realtime"]; - if (cd.has("binds")) - ci.binds=cd["binds"]; - - connections.push_back(ci); - - } - - DVector<String> groups=d.has("groups")?d["groups"].operator DVector<String>():DVector<String>(); - for (int i=0;i<groups.size();i++) { - - node->add_to_group(groups[i],true); - } - -} - - - -Node* SceneInteractiveLoaderObject::load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_save_instance_state,Map<uint32_t,Node*>& owner_map) { - - r_err = OK; - - Node *node=obj->cast_to<Node>(); - - _apply_meta(node,meta,p_loader,connections,r_err,owner_map); - if (r_err!=OK) - return NULL; - - Dictionary d=meta; - - if (p_root) { - NodePath path=d.has("path")?d["path"].operator NodePath():NodePath("."); - - Node *parent=p_root->get_node(path); - if (!parent) { - memdelete(node); - r_err=ERR_FILE_CORRUPT; - ERR_FAIL_COND_V(!parent,NULL); - } - - parent->add_child(node); - - if (d.has("owner_id")) { - //is owner - owner_map[d["owner_id"]]=node; - if (d.has("instance")) - node->set_filename(d["instance"]); - - } - - if (d.has("owner")) { - - uint32_t owner = d["owner"]; - ERR_FAIL_COND_V(!owner_map.has(owner),NULL); - node->set_owner(owner_map[owner]); - } else { - - node->set_owner(p_root); - } - } - - return node; -} - -void SceneInteractiveLoaderObject::_apply_connections(List<ConnectionItem>& connections) { - - int idx=0; - for (List<ConnectionItem>::Element *E=connections.front();E;E=E->next()) { - - ConnectionItem &ci=E->get(); - Node *target = ci.node->get_node(ci.target); - ERR_CONTINUE(!target); - ci.node->connect(ci.signal,target,ci.method,ci.binds,(ci.realtime?0:Object::CONNECT_DEFERRED)|Object::CONNECT_PERSIST); - idx++; - } - -} - -SceneInteractiveLoaderObject::SceneInteractiveLoaderObject(const String &p_path,bool p_save_root_state) { - - error=OK; - path=p_path; - save_instance_state=p_save_root_state; - node_path=p_path; - root=NULL; - stage_max=1; - stage=0; - - - String extension=p_path.extension(); - if (extension=="scn") - extension="bin"; - if (extension=="xscn") - extension="xml"; - - local_path = Globals::get_singleton()->localize_path(p_path); - - loader = ObjectLoader::instance_format_loader(local_path,"SCENE",extension); - - if (!loader) { - - error=ERR_CANT_OPEN; - } - ERR_EXPLAIN("Couldn't load scene: "+p_path); - ERR_FAIL_COND(!loader); - -} - - - -void SceneInteractiveLoaderObject::set_local_path(const String& p_local_path) { - - node_path=p_local_path; -} - -Node *SceneInteractiveLoaderObject::get_scene() { - - if (error==ERR_FILE_EOF) - return root; - return NULL; -} -Error SceneInteractiveLoaderObject::poll() { - - if (error!=OK) - return error; - - Object *obj=NULL; - Variant metav; - Error r_err=loader->load(&obj,metav); - - - if (r_err == ERR_SKIP) { - stage++; - return OK; - }; - - if (r_err==ERR_FILE_EOF) { - memdelete(loader); - error=ERR_FILE_CORRUPT; - ERR_FAIL_COND_V(!root,ERR_FILE_CORRUPT); - _apply_connections(connections); - error=ERR_FILE_EOF; - if (root) - root->set_filename(node_path); - return error; - } - - if (r_err || (!obj && metav.get_type()==Variant::NIL)) { - memdelete(loader); - error=ERR_FILE_CORRUPT; - ERR_EXPLAIN("Object Loader Failed for Scene: "+path); - ERR_FAIL_COND_V( r_err, ERR_FILE_CORRUPT); - ERR_EXPLAIN("Object Loader Failed for Scene: "+path); - ERR_FAIL_COND_V( !obj && metav.get_type()==Variant::NIL,ERR_FILE_CORRUPT); - } - - if (obj) { - if (obj->cast_to<Node>()) { - - Error err; - Node* node = load_node(obj, metav, root, loader,connections,err,save_instance_state,owner_map); - if (err) { - error=ERR_FILE_CORRUPT; - memdelete(loader); - } - - ERR_FAIL_COND_V( err, ERR_FILE_CORRUPT ); - if (!root) - root=node; - } else { - - error=ERR_FILE_CORRUPT; - memdelete(loader); - ERR_EXPLAIN("Loaded something not a node.. (?)"); - ERR_FAIL_V( ERR_FILE_CORRUPT ); - - } - } else { - - // check for instance - Dictionary meta=metav; - if (meta.has("instance")) { - - if (!root) { - - error=ERR_FILE_CORRUPT; - memdelete(loader); - ERR_FAIL_COND_V(!root,ERR_FILE_CORRUPT); - } - - String path = meta["instance"]; - - if (path.find("://")==-1 && path.is_rel_path()) { - // path is relative to file being loaded, so convert to a resource path - path=Globals::get_singleton()->localize_path( - local_path.get_base_dir()+"/"+path); - } - - Node *scene = SceneLoader::load(path); - - if (!scene) { - - error=ERR_FILE_CORRUPT; - memdelete(loader); - ERR_FAIL_COND_V(!scene,ERR_FILE_CORRUPT); - } - - if (save_instance_state) - scene->generate_instance_state(); - - - Error err; - _apply_meta(scene,metav,loader,connections,err,owner_map); - if (err!=OK) { - error=ERR_FILE_CORRUPT; - memdelete(loader); - ERR_FAIL_COND_V(err!=OK,ERR_FILE_CORRUPT); - } - - Node *parent=root; - - if (meta.has("path")) - parent=root->get_node(meta["path"]); - - - if (!parent) { - - error=ERR_FILE_CORRUPT; - memdelete(loader); - ERR_FAIL_COND_V(!parent,ERR_FILE_CORRUPT); - } - - - if (meta.has("override_names") && meta.has("override_values")) { - - DVector<String> override_names=meta["override_names"]; - Array override_values=meta["override_values"]; - - int len = override_names.size(); - if ( len > 0 && len == override_values.size() ) { - - DVector<String>::Read names = override_names.read(); - - for(int i=0;i<len;i++) { - - scene->set(names[i],override_values[i]); - } - - } - - } - - scene->set_filename(path); - - parent->add_child(scene); - scene->set_owner(root); - } - } - - stage++; - error=OK; - return error; - -} -int SceneInteractiveLoaderObject::get_stage() const { - - return stage; -} -int SceneInteractiveLoaderObject::get_stage_count() const { - - return stage_max; -} - - -#endif diff --git a/scene/io/scene_format_object.h b/scene/io/scene_format_object.h deleted file mode 100644 index 3f0bbd4627..0000000000 --- a/scene/io/scene_format_object.h +++ /dev/null @@ -1,128 +0,0 @@ -/*************************************************************************/ -/* scene_format_object.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef SCENE_FORMAT_OBJECT_H -#define SCENE_FORMAT_OBJECT_H - - -#include "scene/main/node.h" -#include "scene/io/scene_saver.h" -#include "scene/io/scene_loader.h" -#include "io/object_saver.h" -#include "io/object_loader.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - - -#ifdef OLD_SCENE_FORMAT_ENABLED - -class SceneFormatSaverObject : public SceneFormatSaver { - - void save_node(const Node* p_root,const Node* p_node,const Node* p_owner,ObjectFormatSaver *p_saver,String p_base_path,uint32_t p_flags,Map<const Node*,uint32_t>& owner_id) const; - -public: - - virtual Error save(const String &p_path,const Node* p_scenezz,uint32_t p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>()); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - virtual ~SceneFormatSaverObject() {} -}; - - - -class SceneFormatLoaderObject : public SceneFormatLoader { - - - struct ConnectionItem { - Node *node; - NodePath target; - StringName method; - StringName signal; - Vector<Variant> binds; - bool realtime; - }; - - Node* load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_root_scene_hint,Map<uint32_t,Node*>& owner_map); - void _apply_connections(List<ConnectionItem>& connections); - void _apply_meta(Node *node, const Variant& meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map); - -public: - - virtual Ref<SceneInteractiveLoader> load_interactive(const String &p_path,bool p_root_scene_hint=false); - virtual Node* load(const String &p_path,bool p_save_root_state=false); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - -}; - - -class SceneInteractiveLoaderObject : public SceneInteractiveLoader { - - OBJ_TYPE(SceneInteractiveLoaderObject,SceneInteractiveLoader); - - struct ConnectionItem { - Node *node; - NodePath target; - StringName method; - StringName signal; - Vector<Variant> binds; - bool realtime; - }; - ObjectFormatLoader *loader; - String path; - String node_path; - String local_path; - Error error; - bool save_instance_state; - List<ConnectionItem> connections; - Map<uint32_t,Node*> owner_map; - Node *root; - int stage_max; - int stage; - - - Node* load_node(Object *obj, const Variant& meta, Node *p_root, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,bool p_root_scene_hint,Map<uint32_t,Node*>& owner_map); - void _apply_connections(List<ConnectionItem>& connections); - void _apply_meta(Node *node, const Variant& meta, ObjectFormatLoader *p_loader,List<ConnectionItem>& connections,Error& r_err,Map<uint32_t,Node*>& owner_map); - -friend class SceneFormatLoaderObject; -public: - - virtual void set_local_path(const String& p_local_path); - virtual Node *get_scene(); - virtual Error poll(); - virtual int get_stage() const; - virtual int get_stage_count() const; - - - SceneInteractiveLoaderObject(const String &p_path,bool p_save_root_state=false); -}; - - - -#endif -#endif diff --git a/scene/io/scene_format_script.cpp b/scene/io/scene_format_script.cpp deleted file mode 100644 index a6f1596d2b..0000000000 --- a/scene/io/scene_format_script.cpp +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************/ -/* scene_format_script.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "scene_format_script.h" -#if 0 -Node* SceneFormatLoaderScript::load(const String &p_path,bool p_save_instance_state) { - - Ref<Script> script = ResourceLoader::load(p_path); - ERR_EXPLAIN("Can't load script-based scene: "+p_path); - ERR_FAIL_COND_V(script.is_null(),NULL); - ERR_EXPLAIN("Script does not instance in a node: "+p_path); - ERR_FAIL_COND_V(script->get_node_type()=="",NULL); - String node_type=script->get_node_type(); - Object *obj = ObjectTypeDB::instance(node_type); - ERR_EXPLAIN("Unknown node type for instancing '"+node_type+"' in script: "+p_path); - ERR_FAIL_COND_V(!obj,NULL); - Node *node = obj->cast_to<Node>(); - if (!node) - memdelete(obj); - ERR_EXPLAIN("Node type '"+node_type+"' not of type 'Node'' in script: "+p_path); - ERR_FAIL_COND_V(!node,NULL); - - node->set_script(script.get_ref_ptr()); - - return node; -} - -void SceneFormatLoaderScript::get_recognized_extensions(List<String> *p_extensions) const { - - for (int i=0;i<ScriptServer::get_language_count();i++) { - - ScriptServer::get_language(i)->get_recognized_extensions(p_extensions); - } -} - - -SceneFormatLoaderScript::SceneFormatLoaderScript() -{ -} -#endif diff --git a/scene/io/scene_format_script.h b/scene/io/scene_format_script.h deleted file mode 100644 index 9bfcc0b1e3..0000000000 --- a/scene/io/scene_format_script.h +++ /dev/null @@ -1,45 +0,0 @@ -/*************************************************************************/ -/* scene_format_script.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef SCENE_FORMAT_SCRIPT_H -#define SCENE_FORMAT_SCRIPT_H - -#include "scene/io/scene_loader.h" -#include "io/resource_loader.h" -#if 0 - -class SceneFormatLoaderScript : public SceneFormatLoader { -public: - - virtual Node* load(const String &p_path,bool p_save_instance_state=false); - virtual void get_recognized_extensions(List<String> *p_extensions) const; - - SceneFormatLoaderScript(); -}; -#endif -#endif // SCENE_FORMAT_SCRIPT_H diff --git a/scene/io/scene_loader.cpp b/scene/io/scene_loader.cpp deleted file mode 100644 index 8615e64ae9..0000000000 --- a/scene/io/scene_loader.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/*************************************************************************/ -/* scene_loader.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "scene_loader.h" -#include "globals.h" -#include "path_remap.h" - -#ifdef OLD_SCENE_FORMAT_ENABLED - -SceneFormatLoader *SceneLoader::loader[MAX_LOADERS]; - -int SceneLoader::loader_count=0; - - -void SceneInteractiveLoader::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("get_scene"),&SceneInteractiveLoader::get_scene); - ObjectTypeDB::bind_method(_MD("poll"),&SceneInteractiveLoader::poll); - ObjectTypeDB::bind_method(_MD("get_stage"),&SceneInteractiveLoader::get_stage); - ObjectTypeDB::bind_method(_MD("get_stage_count"),&SceneInteractiveLoader::get_stage_count); -} - -class SceneInteractiveLoaderDefault : public SceneInteractiveLoader { - - OBJ_TYPE( SceneInteractiveLoaderDefault, SceneInteractiveLoader ); -public: - Node *scene; - - virtual void set_local_path(const String& p_local_path) { scene->set_filename(p_local_path); } - virtual Node *get_scene() { return scene; } - virtual Error poll() { return ERR_FILE_EOF; } - virtual int get_stage() const { return 1; } - virtual int get_stage_count() const { return 1; } - - SceneInteractiveLoaderDefault() {} -}; - - -Ref<SceneInteractiveLoader> SceneFormatLoader::load_interactive(const String &p_path,bool p_root_scene_hint) { - - Node *scene = load(p_path,p_root_scene_hint); - if (!scene) - return Ref<SceneInteractiveLoader>(); - Ref<SceneInteractiveLoaderDefault> sil = Ref<SceneInteractiveLoaderDefault>( memnew( SceneInteractiveLoaderDefault )); - sil->scene=scene; - return sil; -} - - - -bool SceneFormatLoader::recognize(const String& p_extension) const { - - - List<String> extensions; - get_recognized_extensions(&extensions); - for (List<String>::Element *E=extensions.front();E;E=E->next()) { - - if (E->get().nocasecmp_to(p_extension.extension())==0) - return true; - } - - return false; -} - -Ref<SceneInteractiveLoader> SceneLoader::load_interactive(const String &p_path,bool p_save_root_state) { - - String local_path=Globals::get_singleton()->localize_path(p_path); - - String remapped_path = PathRemap::get_singleton()->get_remap(local_path); - String extension=remapped_path.extension(); - - for (int i=0;i<loader_count;i++) { - - if (!loader[i]->recognize(extension)) - continue; - Ref<SceneInteractiveLoader> il = loader[i]->load_interactive(remapped_path,p_save_root_state); - - if (il.is_null() && remapped_path!=local_path) - il = loader[i]->load_interactive(local_path,p_save_root_state); - - ERR_EXPLAIN("Error loading scene: "+local_path); - ERR_FAIL_COND_V(il.is_null(),Ref<SceneInteractiveLoader>()); - il->set_local_path(local_path); - - return il; - } - - ERR_EXPLAIN("No loader found for scene: "+p_path); - ERR_FAIL_V(Ref<SceneInteractiveLoader>()); - return Ref<SceneInteractiveLoader>(); -} - -Node* SceneLoader::load(const String &p_path,bool p_root_scene_hint) { - - String local_path=Globals::get_singleton()->localize_path(p_path); - - String remapped_path = PathRemap::get_singleton()->get_remap(local_path); - String extension=remapped_path.extension(); - - for (int i=0;i<loader_count;i++) { - - if (!loader[i]->recognize(extension)) - continue; - Node*node = loader[i]->load(remapped_path,p_root_scene_hint); - - if (!node && remapped_path!=local_path) - node = loader[i]->load(local_path,p_root_scene_hint); - - ERR_EXPLAIN("Error loading scene: "+local_path); - ERR_FAIL_COND_V(!node,NULL); - node->set_filename(local_path); - - return node; - } - - ERR_EXPLAIN("No loader found for scene: "+p_path); - ERR_FAIL_V(NULL); -} - -void SceneLoader::get_recognized_extensions(List<String> *p_extensions) { - - for (int i=0;i<loader_count;i++) { - - loader[i]->get_recognized_extensions(p_extensions); - } - -} - -void SceneLoader::add_scene_format_loader(SceneFormatLoader *p_format_loader) { - - ERR_FAIL_COND( loader_count >= MAX_LOADERS ); - loader[loader_count++]=p_format_loader; -} - - -#endif diff --git a/scene/io/scene_loader.h b/scene/io/scene_loader.h deleted file mode 100644 index 2562fc0520..0000000000 --- a/scene/io/scene_loader.h +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************/ -/* scene_loader.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef SCENE_LOADER_H -#define SCENE_LOADER_H - -#include "scene/main/node.h" - -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - -#ifdef OLD_SCENE_FORMAT_ENABLED - -class SceneInteractiveLoader : public Reference { - - OBJ_TYPE(SceneInteractiveLoader,Reference); -protected: - - static void _bind_methods(); -public: - - virtual void set_local_path(const String& p_local_path)=0; - virtual Node *get_scene()=0; - virtual Error poll()=0; - virtual int get_stage() const=0; - virtual int get_stage_count() const=0; - - - SceneInteractiveLoader() {} -}; - -class SceneFormatLoader { -public: - - virtual Ref<SceneInteractiveLoader> load_interactive(const String &p_path,bool p_root_scene_hint=false); - virtual Node* load(const String &p_path,bool p_root_scene_hint=false)=0; - virtual void get_recognized_extensions(List<String> *p_extensions) const=0; - bool recognize(const String& p_extension) const; - - virtual ~SceneFormatLoader() {} -}; - -class SceneLoader { - - enum { - MAX_LOADERS=64 - }; - - static SceneFormatLoader *loader[MAX_LOADERS]; - static int loader_count; - -public: - - static Ref<SceneInteractiveLoader> load_interactive(const String &p_path,bool p_save_root_state=false); - static Node* load(const String &p_path,bool p_save_root_state=false); - static void add_scene_format_loader(SceneFormatLoader *p_format_loader); - static void get_recognized_extensions(List<String> *p_extensions); - - -}; - -#endif - -#endif diff --git a/scene/io/scene_saver.cpp b/scene/io/scene_saver.cpp deleted file mode 100644 index f1b503ef27..0000000000 --- a/scene/io/scene_saver.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/*************************************************************************/ -/* scene_saver.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "scene_saver.h" -#include "print_string.h" - -#ifdef OLD_SCENE_FORMAT_ENABLED -SceneFormatSaver *SceneSaver::saver[MAX_SAVERS]; - -int SceneSaver::saver_count=0; - -bool SceneFormatSaver::recognize(const String& p_extension) const { - - - List<String> extensions; - get_recognized_extensions(&extensions); - for (List<String>::Element *E=extensions.front();E;E=E->next()) { - - - if (E->get().nocasecmp_to(p_extension.extension())==0) - return true; - } - - return false; -} - -Error SceneSaver::save(const String &p_path,const Node* p_scene,uint32_t p_flags,const Ref<OptimizedSaver> &p_optimizer) { - - String extension=p_path.extension(); - Error err=ERR_FILE_UNRECOGNIZED; - bool recognized=false; - - for (int i=0;i<saver_count;i++) { - - if (!saver[i]->recognize(extension)) - continue; - recognized=true; - err = saver[i]->save(p_path,p_scene,p_flags,p_optimizer); - if (err == OK ) - return OK; - } - - if (err) { - if (!recognized) { - ERR_EXPLAIN("No saver format found for scene: "+p_path); - } else { - ERR_EXPLAIN("Couldn't save scene: "+p_path); - } - ERR_FAIL_V(err); - } - - return err; -} - -void SceneSaver::get_recognized_extensions(List<String> *p_extensions) { - - for (int i=0;i<saver_count;i++) { - - saver[i]->get_recognized_extensions(p_extensions); - } -} - -void SceneSaver::add_scene_format_saver(SceneFormatSaver *p_format_saver) { - - ERR_FAIL_COND( saver_count >= MAX_SAVERS ); - saver[saver_count++]=p_format_saver; -} - -#endif diff --git a/scene/io/scene_saver.h b/scene/io/scene_saver.h deleted file mode 100644 index 3028dce133..0000000000 --- a/scene/io/scene_saver.h +++ /dev/null @@ -1,80 +0,0 @@ -/*************************************************************************/ -/* scene_saver.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef SCENE_SAVER_H -#define SCENE_SAVER_H - -#include "scene/main/node.h" -#include "io/object_saver.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - - -#ifdef OLD_SCENE_FORMAT_ENABLED - -class SceneFormatSaver { -public: - - virtual Error save(const String &p_path,const Node* p_scen,uint32_t p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>())=0; - virtual void get_recognized_extensions(List<String> *p_extensions) const=0; - bool recognize(const String& p_extension) const; - virtual ~SceneFormatSaver() {} -}; - - - - -class SceneSaver { - - enum { - MAX_SAVERS=64 - }; - - static SceneFormatSaver *saver[MAX_SAVERS]; - static int saver_count; - -public: - enum SaverFlags { - - FLAG_RELATIVE_PATHS=1, - FLAG_BUNDLE_RESOURCES=2, - FLAG_BUNDLE_INSTANCED_SCENES=4, - FLAG_OMIT_EDITOR_PROPERTIES=8, - FLAG_SAVE_BIG_ENDIAN=16 - }; - - static Error save(const String &p_path,const Node* p_scenezz,uint32_t p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>()); - static void add_scene_format_saver(SceneFormatSaver *p_format_saver); - static void get_recognized_extensions(List<String> *p_extensions); -}; - - - -#endif -#endif diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp index 5006f55daf..ae842577a9 100644 --- a/scene/main/canvas_layer.cpp +++ b/scene/main/canvas_layer.cpp @@ -144,7 +144,7 @@ void CanvasLayer::_notification(int p_what) { switch(p_what) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { Node *n = this; vp=NULL; @@ -169,7 +169,7 @@ void CanvasLayer::_notification(int p_what) { } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { VisualServer::get_singleton()->viewport_remove_canvas(viewport,canvas->get_canvas()); viewport=RID(); @@ -180,7 +180,7 @@ void CanvasLayer::_notification(int p_what) { Size2 CanvasLayer::get_viewport_size() const { - if (!is_inside_scene()) + if (!is_inside_tree()) return Size2(1,1); Rect2 r = vp->get_visible_rect(); diff --git a/scene/main/node.cpp b/scene/main/node.cpp index 5d89ee80f1..fbdc87a7cc 100644 --- a/scene/main/node.cpp +++ b/scene/main/node.cpp @@ -28,7 +28,6 @@ /*************************************************************************/ #include "node.h" #include "print_string.h" -#include "scene/io/scene_loader.h" #include "message_queue.h" #include "scene/scene_string_names.h" #include "scene/resources/packed_scene.h" @@ -65,7 +64,7 @@ void Node::_notification(int p_notification) { } } break; - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (data.pause_mode==PAUSE_MODE_INHERIT) { @@ -84,12 +83,12 @@ void Node::_notification(int p_notification) { if (data.unhandled_key_input) add_to_group("_vp_unhandled_key_input"+itos(get_viewport()->get_instance_ID())); - get_scene()->node_count++; + get_tree()->node_count++; } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { - get_scene()->node_count--; + get_tree()->node_count--; if (data.input) remove_from_group("_vp_input"+itos(get_viewport()->get_instance_ID())); if (data.unhandled_input) @@ -105,7 +104,7 @@ void Node::_notification(int p_notification) { Variant::CallError err; get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready,NULL,0); } - //emit_signal(SceneStringNames::get_singleton()->enter_scene); + //emit_signal(SceneStringNames::get_singleton()->enter_tree); } break; case NOTIFICATION_POSTINITIALIZE: { @@ -151,11 +150,11 @@ void Node::_propagate_ready() { } -void Node::_propagate_enter_scene() { - // this needs to happen to all childs before any ENTER_SCENE +void Node::_propagate_enter_tree() { + // this needs to happen to all childs before any enter_tree if (data.parent) { - data.scene=data.parent->data.scene; + data.tree=data.parent->data.tree; data.depth=data.parent->data.depth+1; } else { @@ -166,25 +165,25 @@ void Node::_propagate_enter_scene() { if (!data.viewport) data.viewport = data.parent->data.viewport; - data.inside_scene=true; + data.inside_tree=true; const StringName *K=NULL; while ((K=data.grouped.next(K))) { - data.scene->add_to_group(*K,this); + data.tree->add_to_group(*K,this); } - notification(NOTIFICATION_ENTER_SCENE); + notification(NOTIFICATION_ENTER_TREE); if (get_script_instance()) { Variant::CallError err; - get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_scene,NULL,0); + get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_enter_tree,NULL,0); } - emit_signal(SceneStringNames::get_singleton()->enter_scene); + emit_signal(SceneStringNames::get_singleton()->enter_tree); data.blocked++; @@ -192,8 +191,8 @@ void Node::_propagate_enter_scene() { for (int i=0;i<data.children.size();i++) { - if (!data.children[i]->is_inside_scene()) // could have been added in ENTER_SCENE - data.children[i]->_propagate_enter_scene(); + if (!data.children[i]->is_inside_tree()) // could have been added in enter_tree + data.children[i]->_propagate_enter_tree(); } data.blocked--; @@ -202,7 +201,7 @@ void Node::_propagate_enter_scene() { -void Node::_propagate_exit_scene() { +void Node::_propagate_exit_tree() { //block while removing children @@ -210,7 +209,7 @@ void Node::_propagate_exit_scene() { for (int i=data.children.size()-1;i>=0;i--) { - data.children[i]->_propagate_exit_scene(); + data.children[i]->_propagate_exit_tree(); } data.blocked--; @@ -218,29 +217,29 @@ void Node::_propagate_exit_scene() { if (get_script_instance()) { Variant::CallError err; - get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_scene,NULL,0); + get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree,NULL,0); } - emit_signal(SceneStringNames::get_singleton()->exit_scene); + emit_signal(SceneStringNames::get_singleton()->exit_tree); - notification(NOTIFICATION_EXIT_SCENE,true); - if (data.scene) - data.scene->node_removed(this); + notification(NOTIFICATION_EXIT_TREE,true); + if (data.tree) + data.tree->node_removed(this); // exit groups const StringName *K=NULL; while ((K=data.grouped.next(K))) { - data.scene->remove_from_group(*K,this); + data.tree->remove_from_group(*K,this); } data.viewport = NULL; - if (data.scene) - data.scene->tree_changed(); + if (data.tree) + data.tree->tree_changed(); - data.inside_scene=false; - data.scene=NULL; + data.inside_tree=false; + data.tree=NULL; data.depth=-1; } @@ -261,8 +260,8 @@ void Node::move_child(Node *p_child,int p_pos) { data.children.remove( p_child->data.pos ); data.children.insert( p_pos, p_child ); - if (data.scene) { - data.scene->tree_changed(); + if (data.tree) { + data.tree->tree_changed(); } data.blocked++; @@ -272,6 +271,7 @@ void Node::move_child(Node *p_child,int p_pos) { data.children[i]->data.pos=i; } // notification second + move_child_notify(p_child); for (int i=0;i<data.children.size();i++) { data.children[i]->notification( NOTIFICATION_MOVED_IN_PARENT ); @@ -311,6 +311,11 @@ void Node::remove_child_notify(Node *p_child) { // to be used when not wanted } +void Node::move_child_notify(Node *p_child) { + + // to be used when not wanted +} + void Node::set_fixed_process(bool p_process) { if (data.fixed_process==p_process) @@ -334,7 +339,7 @@ void Node::set_pause_mode(PauseMode p_mode) { bool prev_inherits=data.pause_mode==PAUSE_MODE_INHERIT; data.pause_mode=p_mode; - if (!is_inside_scene()) + if (!is_inside_tree()) return; //pointless if ((data.pause_mode==PAUSE_MODE_INHERIT) == prev_inherits) return; ///nothing changed @@ -373,10 +378,12 @@ void Node::_propagate_pause_owner(Node*p_owner) { bool Node::can_process() const { - ERR_FAIL_COND_V( !is_inside_scene(), false ); + ERR_FAIL_COND_V( !is_inside_tree(), false ); - if (get_scene()->is_paused()) { + if (get_tree()->is_paused()) { + if (data.pause_mode==PAUSE_MODE_STOP) + return false; if (data.pause_mode==PAUSE_MODE_PROCESS) return true; if (data.pause_mode==PAUSE_MODE_INHERIT) { @@ -386,6 +393,9 @@ bool Node::can_process() const { if (data.pause_owner->data.pause_mode==PAUSE_MODE_PROCESS) return true; + + if (data.pause_owner->data.pause_mode==PAUSE_MODE_STOP) + return false; } } @@ -396,8 +406,8 @@ bool Node::can_process() const { float Node::get_fixed_process_delta_time() const { - if (data.scene) - return data.scene->get_fixed_process_time(); + if (data.tree) + return data.tree->get_fixed_process_time(); else return 0; } @@ -420,8 +430,8 @@ void Node::set_process(bool p_idle_process) { float Node::get_process_delta_time() const { - if (data.scene) - return data.scene->get_idle_process_time(); + if (data.tree) + return data.tree->get_idle_process_time(); else return 0; } @@ -443,7 +453,7 @@ void Node::set_process_input(bool p_enable) { return; data.input=p_enable; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (p_enable) @@ -463,7 +473,7 @@ void Node::set_process_unhandled_input(bool p_enable) { if (p_enable==data.unhandled_input) return; data.unhandled_input=p_enable; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (p_enable) @@ -483,7 +493,7 @@ void Node::set_process_unhandled_key_input(bool p_enable) { if (p_enable==data.unhandled_key_input) return; data.unhandled_key_input=p_enable; - if (!is_inside_scene()) + if (!is_inside_tree()) return; if (p_enable) @@ -521,10 +531,10 @@ void Node::set_name(const String& p_name) { data.parent->_validate_child_name(this); } - if (is_inside_scene()) { + if (is_inside_tree()) { emit_signal("renamed"); - get_scene()->tree_changed(); + get_tree()->tree_changed(); } } @@ -631,8 +641,8 @@ void Node::_add_child_nocheck(Node* p_child,const StringName& p_name) { data.children.push_back( p_child ); p_child->data.parent=this; - if (data.scene) { - p_child->_set_scene(data.scene); + if (data.tree) { + p_child->_set_tree(data.tree); } /* Notify */ @@ -720,7 +730,7 @@ void Node::remove_child(Node *p_child) { //if (data.scene) { does not matter - p_child->_set_scene(NULL); + p_child->_set_tree(NULL); //} remove_child_notify(p_child); @@ -756,7 +766,7 @@ Node *Node::get_child(int p_index) const { Node *Node::_get_node(const NodePath& p_path) const { - ERR_FAIL_COND_V( !data.inside_scene && p_path.is_absolute(), NULL ); + ERR_FAIL_COND_V( !data.inside_tree && p_path.is_absolute(), NULL ); Node *current=NULL; Node *root=NULL; @@ -852,8 +862,8 @@ bool Node::is_a_parent_of(const Node *p_node) const { bool Node::is_greater_than(const Node *p_node) const { ERR_FAIL_NULL_V(p_node,false); - ERR_FAIL_COND_V( !data.inside_scene, false ); - ERR_FAIL_COND_V( !p_node->data.inside_scene, false ); + ERR_FAIL_COND_V( !data.inside_tree, false ); + ERR_FAIL_COND_V( !p_node->data.inside_tree, false ); ERR_FAIL_COND_V( data.depth<0, false); ERR_FAIL_COND_V( p_node->data.depth<0, false); @@ -1024,7 +1034,7 @@ NodePath Node::get_path_to(const Node *p_node) const { NodePath Node::get_path() const { - ERR_FAIL_COND_V(!is_inside_scene(),NodePath()); + ERR_FAIL_COND_V(!is_inside_tree(),NodePath()); const Node *n = this; Vector<StringName> path; @@ -1053,8 +1063,8 @@ void Node::add_to_group(const StringName& p_identifier,bool p_persistent) { GroupData gd; - if (data.scene) - data.scene->add_to_group(p_identifier,this); + if (data.tree) + data.tree->add_to_group(p_identifier,this); gd.persistent=p_persistent; @@ -1071,8 +1081,8 @@ void Node::remove_from_group(const StringName& p_identifier) { ERR_FAIL_COND(!g); - if (data.scene) - data.scene->remove_from_group(p_identifier,this); + if (data.tree) + data.tree->remove_from_group(p_identifier,this); data.grouped.erase(p_identifier); @@ -1132,7 +1142,7 @@ void Node::_propagate_reverse_notification(int p_notification) { void Node::_propagate_deferred_notification(int p_notification, bool p_reverse) { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); data.blocked++; @@ -1235,7 +1245,7 @@ void Node::generate_instance_state() { for( List<PropertyInfo>::Element *E=properties.front();E;E=E->next() ) { PropertyInfo &pi=E->get(); - if (!(pi.usage&PROPERTY_USAGE_EDITOR) || !(pi.usage&PROPERTY_USAGE_STORAGE)) + if ((pi.usage&PROPERTY_USAGE_NO_INSTANCE_STATE) || !(pi.usage&PROPERTY_USAGE_EDITOR) || !(pi.usage&PROPERTY_USAGE_STORAGE)) continue; data.instance_state[pi.name]=get(pi.name); @@ -1425,6 +1435,20 @@ Node *Node::duplicate_and_reown(const Map<Node*,Node*>& p_reown_map) const { node->set_name(get_name()); + List<PropertyInfo> plist; + + get_property_list(&plist); + + for(List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { + + if (!(E->get().usage&PROPERTY_USAGE_STORAGE)) + continue; + String name = E->get().name; + node->set( name, get(name) ); + + } + + for(int i=0;i<get_child_count();i++) { get_child(i)->_duplicate_and_reown(node,p_reown_map); @@ -1611,29 +1635,29 @@ Node *Node::get_node_and_resource(const NodePath& p_path,RES& r_res) const { return node; } -void Node::_set_scene(SceneMainLoop *p_scene) { +void Node::_set_tree(SceneTree *p_tree) { - SceneMainLoop *tree_changed_a=NULL; - SceneMainLoop *tree_changed_b=NULL; + SceneTree *tree_changed_a=NULL; + SceneTree *tree_changed_b=NULL; // ERR_FAIL_COND(p_scene && data.parent && !data.parent->data.scene); //nobug if both are null - if (data.scene) { - _propagate_exit_scene(); + if (data.tree) { + _propagate_exit_tree(); - tree_changed_a=data.scene; + tree_changed_a=data.tree; } - data.scene=p_scene; + data.tree=p_tree; - if (data.scene) { + if (data.tree) { - _propagate_enter_scene(); + _propagate_enter_tree(); _propagate_ready(); //reverse_notification(NOTIFICATION_READY); - tree_changed_b=data.scene; + tree_changed_b=data.tree; } @@ -1651,7 +1675,7 @@ static void _Node_debug_sn(Object *p_obj) { if (!n) return; - if (n->is_inside_scene()) + if (n->is_inside_tree()) return; Node *p=n; @@ -1683,8 +1707,8 @@ void Node::print_stray_nodes() { void Node::queue_delete() { - ERR_FAIL_COND( !is_inside_scene() ); - get_scene()->queue_delete(this); + ERR_FAIL_COND( !is_inside_tree() ); + get_tree()->queue_delete(this); } Array Node::_get_children() const { @@ -1712,6 +1736,26 @@ NodePath Node::get_import_path() const { #endif +static void _add_nodes_to_options(const Node *p_base,const Node *p_node,List<String>*r_options) { + + if (p_node!=p_base && !p_node->get_owner()) + return; + String n = p_base->get_path_to(p_node); + r_options->push_back("\""+n+"\""); + for(int i=0;i<p_node->get_child_count();i++) { + _add_nodes_to_options(p_base,p_node->get_child(i),r_options); + } +} + +void Node::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const { + + String pf=p_function; + if ((pf=="has_node" || pf=="get_node") && p_idx==0) { + + _add_nodes_to_options(this,this,r_options); + } + Object::get_argument_options(p_function,p_idx,r_options); +} void Node::_bind_methods() { @@ -1729,7 +1773,7 @@ void Node::_bind_methods() { 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); - ObjectTypeDB::bind_method(_MD("is_inside_scene"),&Node::is_inside_scene); + ObjectTypeDB::bind_method(_MD("is_inside_tree"),&Node::is_inside_tree); ObjectTypeDB::bind_method(_MD("is_a_parent_of","node:Node"),&Node::is_a_parent_of); ObjectTypeDB::bind_method(_MD("is_greater_than","node:Node"),&Node::is_greater_than); ObjectTypeDB::bind_method(_MD("get_path"),&Node::get_path); @@ -1766,7 +1810,7 @@ void Node::_bind_methods() { ObjectTypeDB::bind_method(_MD("print_stray_nodes"),&Node::_print_stray_nodes); ObjectTypeDB::bind_method(_MD("get_position_in_parent"),&Node::get_position_in_parent); - ObjectTypeDB::bind_method(_MD("get_scene:SceneMainLoop"),&Node::get_scene); + ObjectTypeDB::bind_method(_MD("get_tree:SceneTree"),&Node::get_tree); ObjectTypeDB::bind_method(_MD("duplicate:Node"),&Node::duplicate); ObjectTypeDB::bind_method(_MD("replace_by","node:Node","keep_data"),&Node::replace_by,DEFVAL(false)); @@ -1781,8 +1825,8 @@ void Node::_bind_methods() { #endif - BIND_CONSTANT( NOTIFICATION_ENTER_SCENE ); - BIND_CONSTANT( NOTIFICATION_EXIT_SCENE ); + BIND_CONSTANT( NOTIFICATION_ENTER_TREE ); + BIND_CONSTANT( NOTIFICATION_EXIT_TREE ); BIND_CONSTANT( NOTIFICATION_MOVED_IN_PARENT ); //BIND_CONSTANT( NOTIFICATION_PARENT_DECONFIGURED ); BIND_CONSTANT( NOTIFICATION_READY ); @@ -1799,8 +1843,8 @@ void Node::_bind_methods() { BIND_CONSTANT( PAUSE_MODE_PROCESS ); ADD_SIGNAL( MethodInfo("renamed") ); - ADD_SIGNAL( MethodInfo("enter_scene") ); - ADD_SIGNAL( MethodInfo("exit_scene") ); + ADD_SIGNAL( MethodInfo("enter_tree") ); + ADD_SIGNAL( MethodInfo("exit_tree") ); // ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/process" ),_SCS("set_process"),_SCS("is_processing") ); // ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/fixed_process" ), _SCS("set_fixed_process"),_SCS("is_fixed_processing") ); @@ -1810,8 +1854,8 @@ void Node::_bind_methods() { BIND_VMETHOD( MethodInfo("_process",PropertyInfo(Variant::REAL,"delta")) ); BIND_VMETHOD( MethodInfo("_fixed_process",PropertyInfo(Variant::REAL,"delta")) ); - BIND_VMETHOD( MethodInfo("_enter_scene") ); - BIND_VMETHOD( MethodInfo("_exit_scene") ); + BIND_VMETHOD( MethodInfo("_enter_tree") ); + BIND_VMETHOD( MethodInfo("_exit_tree") ); BIND_VMETHOD( MethodInfo("_ready") ); BIND_VMETHOD( MethodInfo("_input",PropertyInfo(Variant::INPUT_EVENT,"event")) ); BIND_VMETHOD( MethodInfo("_unhandled_input",PropertyInfo(Variant::INPUT_EVENT,"event")) ); @@ -1828,10 +1872,10 @@ Node::Node() { data.depth=-1; data.blocked=0; data.parent=NULL; - data.scene=NULL; + data.tree=NULL; data.fixed_process=false; data.idle_process=false; - data.inside_scene=false; + data.inside_tree=false; data.owner=NULL; data.OW=NULL; diff --git a/scene/main/node.h b/scene/main/node.h index f1ecf497e0..47f49eb625 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -80,8 +80,8 @@ private: int depth; int blocked; // safeguard that throws an error when attempting to modify the tree in a harmful way while being traversed. StringName name; - SceneMainLoop *scene; - bool inside_scene; + SceneTree *tree; + bool inside_tree; #ifdef TOOLS_ENABLED NodePath import_path; //path used when imported, used by scene editors to keep tracking #endif @@ -118,9 +118,9 @@ private: void _propagate_reverse_notification(int p_notification); void _propagate_deferred_notification(int p_notification, bool p_reverse); - void _propagate_enter_scene(); + void _propagate_enter_tree(); void _propagate_ready(); - void _propagate_exit_scene(); + void _propagate_exit_tree(); void _propagate_validate_owner(); void _print_stray_nodes(); void _propagate_pause_owner(Node*p_owner); @@ -130,9 +130,9 @@ private: Array _get_children() const; Array _get_groups() const; -friend class SceneMainLoop; +friend class SceneTree; - void _set_scene(SceneMainLoop *p_scene); + void _set_tree(SceneTree *p_tree); protected: void _block() { data.blocked++; } @@ -142,6 +142,7 @@ protected: virtual void add_child_notify(Node *p_child); virtual void remove_child_notify(Node *p_child); + virtual void move_child_notify(Node *p_child); void remove_and_delete_child(Node *p_child); void _propagate_replace_owner(Node *p_owner,Node* p_by_owner); @@ -158,8 +159,8 @@ public: enum { // you can make your own, but don't use the same numbers as other notifications in other nodes - NOTIFICATION_ENTER_SCENE=10, - NOTIFICATION_EXIT_SCENE =11, + NOTIFICATION_ENTER_TREE=10, + NOTIFICATION_EXIT_TREE =11, NOTIFICATION_MOVED_IN_PARENT =12, NOTIFICATION_READY=13, //NOTIFICATION_PARENT_DECONFIGURED =15, - it's confusing, it's going away @@ -187,9 +188,9 @@ public: Node *get_node_and_resource(const NodePath& p_path,RES& r_res) const; Node *get_parent() const; - _FORCE_INLINE_ SceneMainLoop *get_scene() const { ERR_FAIL_COND_V( !data.scene, NULL ); return data.scene; } + _FORCE_INLINE_ SceneTree *get_tree() const { ERR_FAIL_COND_V( !data.tree, NULL ); return data.tree; } - _FORCE_INLINE_ bool is_inside_scene() const { return data.inside_scene; } + _FORCE_INLINE_ bool is_inside_tree() const { return data.inside_tree; } bool is_a_parent_of(const Node *p_node) const; bool is_greater_than(const Node *p_node) const; @@ -283,6 +284,7 @@ public: NodePath get_import_path() const; #endif + void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; _FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; } diff --git a/scene/main/scene_main_loop.cpp b/scene/main/scene_main_loop.cpp index bcdc50c880..ed3e419359 100644 --- a/scene/main/scene_main_loop.cpp +++ b/scene/main/scene_main_loop.cpp @@ -43,13 +43,13 @@ #include "viewport.h" -void SceneMainLoop::tree_changed() { +void SceneTree::tree_changed() { tree_version++; emit_signal(tree_changed_name); } -void SceneMainLoop::node_removed(Node *p_node) { +void SceneTree::node_removed(Node *p_node) { emit_signal(node_removed_name,p_node); if (call_lock>0) @@ -59,7 +59,7 @@ void SceneMainLoop::node_removed(Node *p_node) { } -void SceneMainLoop::add_to_group(const StringName& p_group, Node *p_node) { +void SceneTree::add_to_group(const StringName& p_group, Node *p_node) { Map<StringName,Group>::Element *E=group_map.find(p_group); if (!E) { @@ -74,7 +74,7 @@ void SceneMainLoop::add_to_group(const StringName& p_group, Node *p_node) { E->get().last_tree_version=0; } -void SceneMainLoop::remove_from_group(const StringName& p_group, Node *p_node) { +void SceneTree::remove_from_group(const StringName& p_group, Node *p_node) { Map<StringName,Group>::Element *E=group_map.find(p_group); ERR_FAIL_COND(!E); @@ -85,7 +85,7 @@ void SceneMainLoop::remove_from_group(const StringName& p_group, Node *p_node) { group_map.erase(E); } -void SceneMainLoop::_flush_transform_notifications() { +void SceneTree::_flush_transform_notifications() { SelfList<Node>* n = xform_change_list.first(); while(n) { @@ -98,7 +98,7 @@ void SceneMainLoop::_flush_transform_notifications() { } } -void SceneMainLoop::_flush_ugc() { +void SceneTree::_flush_ugc() { ugc_locked=true; @@ -118,7 +118,7 @@ void SceneMainLoop::_flush_ugc() { ugc_locked=false; } -void SceneMainLoop::_update_group_order(Group& g) { +void SceneTree::_update_group_order(Group& g) { if (g.last_tree_version==tree_version) return; @@ -134,7 +134,7 @@ void SceneMainLoop::_update_group_order(Group& g) { } -void SceneMainLoop::call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,VARIANT_ARG_DECLARE) { +void SceneTree::call_group(uint32_t p_call_flags,const StringName& p_group,const StringName& p_function,VARIANT_ARG_DECLARE) { Map<StringName,Group>::Element *E=group_map.find(p_group); if (!E) @@ -216,7 +216,7 @@ void SceneMainLoop::call_group(uint32_t p_call_flags,const StringName& p_group,c call_skip.clear(); } -void SceneMainLoop::notify_group(uint32_t p_call_flags,const StringName& p_group,int p_notification) { +void SceneTree::notify_group(uint32_t p_call_flags,const StringName& p_group,int p_notification) { Map<StringName,Group>::Element *E=group_map.find(p_group); if (!E) @@ -266,7 +266,7 @@ void SceneMainLoop::notify_group(uint32_t p_call_flags,const StringName& p_group call_skip.clear(); } -void SceneMainLoop::set_group(uint32_t p_call_flags,const StringName& p_group,const String& p_name,const Variant& p_value) { +void SceneTree::set_group(uint32_t p_call_flags,const StringName& p_group,const String& p_name,const Variant& p_value) { Map<StringName,Group>::Element *E=group_map.find(p_group); if (!E) @@ -316,12 +316,12 @@ void SceneMainLoop::set_group(uint32_t p_call_flags,const StringName& p_group,co call_skip.clear(); } -void SceneMainLoop::set_input_as_handled() { +void SceneTree::set_input_as_handled() { input_handled=true; } -void SceneMainLoop::input_text( const String& p_text ) { +void SceneTree::input_text( const String& p_text ) { root_lock++; @@ -330,16 +330,20 @@ void SceneMainLoop::input_text( const String& p_text ) { } -void SceneMainLoop::input_event( const InputEvent& p_event ) { +void SceneTree::input_event( const InputEvent& p_event ) { + if (is_editor_hint() && (p_event.type==InputEvent::JOYSTICK_MOTION || p_event.type==InputEvent::JOYSTICK_BUTTON)) + return; //avoid joy input on editor + root_lock++; - last_id=p_event.ID; + //last_id=p_event.ID; input_handled=false; InputEvent ev = p_event; + ev.ID=++last_id; //this should work better #if 0 switch(ev.type) { @@ -393,7 +397,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) { #endif - MainLoop::input_event(p_event); + MainLoop::input_event(ev); #if 0 _call_input_pause("input","_input",ev); @@ -415,7 +419,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) { //transform for the rest #else - call_group(GROUP_CALL_REALTIME,"_viewports","_vp_input",p_event); //special one for GUI, as controls use their own process check + call_group(GROUP_CALL_REALTIME,"_viewports","_vp_input",ev); //special one for GUI, as controls use their own process check #endif if (ScriptDebugger::get_singleton() && ScriptDebugger::get_singleton()->is_remote() && ev.type==InputEvent::KEY && ev.key.pressed && !ev.key.echo && ev.key.scancode==KEY_F8) { @@ -440,7 +444,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) { } #else - call_group(GROUP_CALL_REALTIME,"_viewports","_vp_unhandled_input",p_event); //special one for GUI, as controls use their own process check + call_group(GROUP_CALL_REALTIME,"_viewports","_vp_unhandled_input",ev); //special one for GUI, as controls use their own process check #endif input_handled=true; @@ -455,7 +459,7 @@ void SceneMainLoop::input_event( const InputEvent& p_event ) { } -void SceneMainLoop::init() { +void SceneTree::init() { //_quit=false; accept_quit=true; @@ -466,12 +470,12 @@ void SceneMainLoop::init() { editor_hint=false; pause=false; - root->_set_scene(this); + root->_set_tree(this); MainLoop::init(); } -bool SceneMainLoop::iteration(float p_time) { +bool SceneTree::iteration(float p_time) { root_lock++; @@ -496,7 +500,7 @@ bool SceneMainLoop::iteration(float p_time) { return _quit; } -bool SceneMainLoop::idle(float p_time){ +bool SceneTree::idle(float p_time){ // print_line("ram: "+itos(OS::get_singleton()->get_static_memory_usage())+" sram: "+itos(OS::get_singleton()->get_dynamic_memory_usage())); @@ -538,7 +542,7 @@ bool SceneMainLoop::idle(float p_time){ return _quit; } -void SceneMainLoop::finish() { +void SceneTree::finish() { _flush_delete_queue(); @@ -549,7 +553,7 @@ void SceneMainLoop::finish() { MainLoop::finish(); if (root) { - root->_set_scene(NULL); + root->_set_tree(NULL); memdelete(root); //delete root } @@ -564,12 +568,12 @@ void SceneMainLoop::finish() { } -void SceneMainLoop::quit() { +void SceneTree::quit() { _quit=true; } -void SceneMainLoop::_notification(int p_notification) { +void SceneTree::_notification(int p_notification) { @@ -602,22 +606,22 @@ void SceneMainLoop::_notification(int p_notification) { }; -void SceneMainLoop::set_auto_accept_quit(bool p_enable) { +void SceneTree::set_auto_accept_quit(bool p_enable) { accept_quit=p_enable; } -void SceneMainLoop::set_editor_hint(bool p_enabled) { +void SceneTree::set_editor_hint(bool p_enabled) { editor_hint=p_enabled; } -bool SceneMainLoop::is_editor_hint() const { +bool SceneTree::is_editor_hint() const { return editor_hint; } -void SceneMainLoop::set_pause(bool p_enabled) { +void SceneTree::set_pause(bool p_enabled) { if (p_enabled==pause) return; @@ -628,12 +632,12 @@ void SceneMainLoop::set_pause(bool p_enabled) { get_root()->propagate_notification(p_enabled ? Node::NOTIFICATION_PAUSED : Node::NOTIFICATION_UNPAUSED); } -bool SceneMainLoop::is_paused() const { +bool SceneTree::is_paused() const { return pause; } -void SceneMainLoop::_call_input_pause(const StringName& p_group,const StringName& p_method,const InputEvent& p_input) { +void SceneTree::_call_input_pause(const StringName& p_group,const StringName& p_method,const InputEvent& p_input) { Map<StringName,Group>::Element *E=group_map.find(p_group); if (!E) @@ -678,7 +682,7 @@ void SceneMainLoop::_call_input_pause(const StringName& p_group,const StringName call_skip.clear(); } -void SceneMainLoop::_notify_group_pause(const StringName& p_group,int p_notification) { +void SceneTree::_notify_group_pause(const StringName& p_group,int p_notification) { Map<StringName,Group>::Element *E=group_map.find(p_group); if (!E) @@ -728,13 +732,13 @@ void SceneMainLoop::_update_listener_2d() { } */ -uint32_t SceneMainLoop::get_last_event_id() const { +uint32_t SceneTree::get_last_event_id() const { return last_id; } -Variant SceneMainLoop::_call_group(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { +Variant SceneTree::_call_group(const Variant** p_args, int p_argcount, Variant::CallError& r_error) { r_error.error=Variant::CallError::CALL_OK; @@ -759,13 +763,13 @@ Variant SceneMainLoop::_call_group(const Variant** p_args, int p_argcount, Varia } -int64_t SceneMainLoop::get_frame() const { +int64_t SceneTree::get_frame() const { return current_frame; } -Array SceneMainLoop::_get_nodes_in_group(const StringName& p_group) { +Array SceneTree::_get_nodes_in_group(const StringName& p_group) { Array ret; Map<StringName,Group>::Element *E=group_map.find(p_group); @@ -788,7 +792,7 @@ Array SceneMainLoop::_get_nodes_in_group(const StringName& p_group) { return ret; } -void SceneMainLoop::get_nodes_in_group(const StringName& p_group,List<Node*> *p_list) { +void SceneTree::get_nodes_in_group(const StringName& p_group,List<Node*> *p_list) { Map<StringName,Group>::Element *E=group_map.find(p_group); @@ -818,9 +822,9 @@ static void _fill_array(Node *p_node, Array& array, int p_level) { } } -void SceneMainLoop::_debugger_request_tree(void *self) { +void SceneTree::_debugger_request_tree(void *self) { - SceneMainLoop *sml = (SceneMainLoop *)self; + SceneTree *sml = (SceneTree *)self; Array arr; _fill_array(sml->root,arr,0); @@ -828,7 +832,7 @@ void SceneMainLoop::_debugger_request_tree(void *self) { } -void SceneMainLoop::_flush_delete_queue() { +void SceneTree::_flush_delete_queue() { _THREAD_SAFE_METHOD_ @@ -842,7 +846,7 @@ void SceneMainLoop::_flush_delete_queue() { } } -void SceneMainLoop::queue_delete(Object *p_object) { +void SceneTree::queue_delete(Object *p_object) { _THREAD_SAFE_METHOD_ ERR_FAIL_NULL(p_object); @@ -850,13 +854,13 @@ void SceneMainLoop::queue_delete(Object *p_object) { } -int SceneMainLoop::get_node_count() const { +int SceneTree::get_node_count() const { return node_count; } -void SceneMainLoop::_update_root_rect() { +void SceneTree::_update_root_rect() { if (stretch_mode==STRETCH_MODE_DISABLED) { @@ -959,7 +963,7 @@ void SceneMainLoop::_update_root_rect() { } -void SceneMainLoop::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize) { +void SceneTree::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize) { stretch_mode=p_mode; stretch_aspect=p_aspect; @@ -968,35 +972,51 @@ void SceneMainLoop::set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect } -void SceneMainLoop::_bind_methods() { +#ifdef TOOLS_ENABLED +void SceneTree::set_edited_scene_root(Node *p_node) { + edited_scene_root=p_node; +} + +Node *SceneTree::get_edited_scene_root() const { + + return edited_scene_root; +} +#endif + + +void SceneTree::_bind_methods() { //ObjectTypeDB::bind_method(_MD("call_group","call_flags","group","method","arg1","arg2"),&SceneMainLoop::_call_group,DEFVAL(Variant()),DEFVAL(Variant())); - ObjectTypeDB::bind_method(_MD("notify_group","call_flags","group","notification"),&SceneMainLoop::notify_group); - ObjectTypeDB::bind_method(_MD("set_group","call_flags","group","property","value"),&SceneMainLoop::set_group); + ObjectTypeDB::bind_method(_MD("notify_group","call_flags","group","notification"),&SceneTree::notify_group); + ObjectTypeDB::bind_method(_MD("set_group","call_flags","group","property","value"),&SceneTree::set_group); - ObjectTypeDB::bind_method(_MD("get_nodes_in_group"),&SceneMainLoop::_get_nodes_in_group); + ObjectTypeDB::bind_method(_MD("get_nodes_in_group"),&SceneTree::_get_nodes_in_group); - ObjectTypeDB::bind_method(_MD("get_root:Viewport"),&SceneMainLoop::get_root); + ObjectTypeDB::bind_method(_MD("get_root:Viewport"),&SceneTree::get_root); - ObjectTypeDB::bind_method(_MD("set_auto_accept_quit","enabled"),&SceneMainLoop::set_auto_accept_quit); + ObjectTypeDB::bind_method(_MD("set_auto_accept_quit","enabled"),&SceneTree::set_auto_accept_quit); - ObjectTypeDB::bind_method(_MD("set_editor_hint","enable"),&SceneMainLoop::set_editor_hint); - ObjectTypeDB::bind_method(_MD("is_editor_hint"),&SceneMainLoop::is_editor_hint); + ObjectTypeDB::bind_method(_MD("set_editor_hint","enable"),&SceneTree::set_editor_hint); + ObjectTypeDB::bind_method(_MD("is_editor_hint"),&SceneTree::is_editor_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); +#endif - ObjectTypeDB::bind_method(_MD("set_pause","enable"),&SceneMainLoop::set_pause); - ObjectTypeDB::bind_method(_MD("is_paused"),&SceneMainLoop::is_paused); - ObjectTypeDB::bind_method(_MD("set_input_as_handled"),&SceneMainLoop::set_input_as_handled); + ObjectTypeDB::bind_method(_MD("set_pause","enable"),&SceneTree::set_pause); + ObjectTypeDB::bind_method(_MD("is_paused"),&SceneTree::is_paused); + ObjectTypeDB::bind_method(_MD("set_input_as_handled"),&SceneTree::set_input_as_handled); - ObjectTypeDB::bind_method(_MD("get_node_count"),&SceneMainLoop::get_node_count); - ObjectTypeDB::bind_method(_MD("get_frame"),&SceneMainLoop::get_frame); - ObjectTypeDB::bind_method(_MD("quit"),&SceneMainLoop::quit); + ObjectTypeDB::bind_method(_MD("get_node_count"),&SceneTree::get_node_count); + ObjectTypeDB::bind_method(_MD("get_frame"),&SceneTree::get_frame); + ObjectTypeDB::bind_method(_MD("quit"),&SceneTree::quit); - ObjectTypeDB::bind_method(_MD("set_screen_stretch","mode","aspect","minsize"),&SceneMainLoop::set_screen_stretch); + ObjectTypeDB::bind_method(_MD("set_screen_stretch","mode","aspect","minsize"),&SceneTree::set_screen_stretch); - ObjectTypeDB::bind_method(_MD("queue_delete","obj"),&SceneMainLoop::queue_delete); + ObjectTypeDB::bind_method(_MD("queue_delete","obj"),&SceneTree::queue_delete); MethodInfo mi; @@ -1010,7 +1030,7 @@ void SceneMainLoop::_bind_methods() { defargs.push_back(Variant()); } - ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneMainLoop::_call_group,mi,defargs); + ObjectTypeDB::bind_native_method(METHOD_FLAGS_DEFAULT,"call_group",&SceneTree::_call_group,mi,defargs); ADD_SIGNAL( MethodInfo("tree_changed") ); ADD_SIGNAL( MethodInfo("node_removed",PropertyInfo( Variant::OBJECT, "node") ) ); @@ -1031,14 +1051,14 @@ void SceneMainLoop::_bind_methods() { } -SceneMainLoop::SceneMainLoop() { +SceneTree::SceneTree() { _quit=false; initialized=false; tree_version=1; fixed_process_time=1; idle_process_time=1; - last_id=0; + last_id=1; root=NULL; current_frame=0; tree_changed_name="tree_changed"; @@ -1069,13 +1089,17 @@ SceneMainLoop::SceneMainLoop() { root->set_physics_object_picking(GLOBAL_DEF("physics/enable_object_picking",true)); +#ifdef TOOLS_ENABLED + edited_scene_root=NULL; +#endif + ADD_SIGNAL( MethodInfo("idle_frame")); ADD_SIGNAL( MethodInfo("fixed_frame")); } -SceneMainLoop::~SceneMainLoop() { +SceneTree::~SceneTree() { } diff --git a/scene/main/scene_main_loop.h b/scene/main/scene_main_loop.h index 493644d2bc..31a823ab1a 100644 --- a/scene/main/scene_main_loop.h +++ b/scene/main/scene_main_loop.h @@ -41,16 +41,16 @@ */ -class SceneMainLoop; +class SceneTree; class Node; class Viewport; -class SceneMainLoop : public MainLoop { +class SceneTree : public MainLoop { _THREAD_SAFE_CLASS_ - OBJ_TYPE( SceneMainLoop, MainLoop ); + OBJ_TYPE( SceneTree, MainLoop ); public: @@ -102,6 +102,9 @@ private: int64_t current_frame; int node_count; +#ifdef TOOLS_ENABLED + Node *edited_scene_root; +#endif struct UGCall { StringName group; @@ -223,15 +226,22 @@ public: void set_screen_stretch(StretchMode p_mode,StretchAspect p_aspect,const Size2 p_minsize); + //void change_scene(const String& p_path); + //Node *get_loaded_scene(); + +#ifdef TOOLS_ENABLED + void set_edited_scene_root(Node *p_node); + Node *get_edited_scene_root() const; +#endif - SceneMainLoop(); - ~SceneMainLoop(); + SceneTree(); + ~SceneTree(); }; -VARIANT_ENUM_CAST( SceneMainLoop::StretchMode ); -VARIANT_ENUM_CAST( SceneMainLoop::StretchAspect ); +VARIANT_ENUM_CAST( SceneTree::StretchMode ); +VARIANT_ENUM_CAST( SceneTree::StretchAspect ); diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp index 25d1c8530e..f718a09577 100644 --- a/scene/main/timer.cpp +++ b/scene/main/timer.cpp @@ -36,8 +36,13 @@ void Timer::_notification(int p_what) { case NOTIFICATION_READY: { - if (autostart) + if (autostart) { +#ifdef TOOLS_ENABLED + if (get_tree()->is_editor_hint() && get_tree()->get_edited_scene_root() && (get_tree()->get_edited_scene_root()==this || get_tree()->get_edited_scene_root()->is_a_parent_of(this))) + break; +#endif start(); + } } break; case NOTIFICATION_PROCESS: { diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 92dcef803c..e6c787cf9e 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -95,8 +95,8 @@ void Viewport::_update_stretch_transform() { if (size_override_stretch && size_override) { - print_line("sive override size "+size_override_size); - print_line("rect size "+rect.size); + //print_line("sive override size "+size_override_size); + //print_line("rect size "+rect.size); stretch_transform=Matrix32(); Size2 scale = rect.size/(size_override_size+size_override_margin*2); stretch_transform.scale(scale); @@ -113,7 +113,7 @@ void Viewport::_update_stretch_transform() { void Viewport::_update_rect() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; Node *parent = get_parent(); @@ -135,7 +135,9 @@ void Viewport::_update_rect() { } vr.width=rect.size.width; vr.height=rect.size.height; + VisualServer::get_singleton()->viewport_set_rect(viewport,vr); + last_vp_rect=rect; if (canvas_item.is_valid()) { VisualServer::get_singleton()->canvas_item_set_custom_rect(canvas_item,true,rect); @@ -164,13 +166,16 @@ void Viewport::_parent_visibility_changed() { Control *c = parent->cast_to<Control>(); VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,c->is_visible()); + + _update_listener(); + _update_listener_2d(); } } -void Viewport::_vp_enter_scene() { +void Viewport::_vp_enter_tree() { Node *parent = get_parent(); //none? @@ -195,7 +200,7 @@ void Viewport::_vp_enter_scene() { } -void Viewport::_vp_exit_scene() { +void Viewport::_vp_exit_tree() { Node *parent = get_parent(); if (parent && parent->cast_to<Control>()) { @@ -226,19 +231,19 @@ void Viewport::_vp_exit_scene() { void Viewport::update_worlds() { - if (!is_inside_scene()) + if (!is_inside_tree()) return; Rect2 xformed_rect = (global_canvas_transform * canvas_transform).affine_inverse().xform(get_visible_rect()); find_world_2d()->_update_viewport(this,xformed_rect); find_world_2d()->_update(); - find_world()->_update(get_scene()->get_frame()); + find_world()->_update(get_tree()->get_frame()); } void Viewport::_test_new_mouseover(ObjectID new_collider) { - +#ifndef _3D_DISABLED if (new_collider!=physics_object_over) { if (physics_object_over) { @@ -266,7 +271,7 @@ void Viewport::_test_new_mouseover(ObjectID new_collider) { physics_object_over=new_collider; } - +#endif } @@ -275,11 +280,11 @@ void Viewport::_notification(int p_what) { switch( p_what ) { - case NOTIFICATION_ENTER_SCENE: { + case NOTIFICATION_ENTER_TREE: { if (!render_target) - _vp_enter_scene(); + _vp_enter_tree(); this->parent=NULL; Node *parent=get_parent(); @@ -329,7 +334,7 @@ void Viewport::_notification(int p_what) { } #endif } break; - case NOTIFICATION_EXIT_SCENE: { + case NOTIFICATION_EXIT_TREE: { @@ -337,7 +342,7 @@ void Viewport::_notification(int p_what) { world_2d->_remove_viewport(this); if (!render_target) - _vp_exit_scene(); + _vp_exit_tree(); VisualServer::get_singleton()->viewport_set_scenario(viewport,RID()); SpatialSoundServer::get_singleton()->listener_set_space(listener,RID()); @@ -348,7 +353,7 @@ void Viewport::_notification(int p_what) { case NOTIFICATION_FIXED_PROCESS: { if (physics_object_picking) { - +#ifndef _3D_DISABLED Vector2 last_pos(1e20,1e20); CollisionObject *last_object; ObjectID last_id=0; @@ -394,7 +399,7 @@ void Viewport::_notification(int p_what) { if (obj) { CollisionObject *co = obj->cast_to<CollisionObject>(); if (co) { - co->_input_event(ev,Vector3(),Vector3(),0); + co->_input_event(camera,ev,Vector3(),Vector3(),0); captured=true; if (ev.type==InputEvent::MOUSE_BUTTON && ev.mouse_button.button_index==1 && !ev.mouse_button.pressed) { physics_object_capture=0; @@ -416,7 +421,7 @@ void Viewport::_notification(int p_what) { if (last_id) { if (ObjectDB::get_instance(last_id)) { //good, exists - last_object->_input_event(ev,result.position,result.normal,result.shape); + last_object->_input_event(camera,ev,result.position,result.normal,result.shape); if (last_object->get_capture_input_on_drag() && ev.type==InputEvent::MOUSE_BUTTON && ev.mouse_button.button_index==1 && ev.mouse_button.pressed) { physics_object_capture=last_id; } @@ -440,10 +445,13 @@ void Viewport::_notification(int p_what) { bool col = space->intersect_ray(from,from+dir*10000,result,Set<RID>(),0xFFFFFFFF,0xFFFFFFFF); ObjectID new_collider=0; if (col) { + if (result.collider) { + CollisionObject *co = result.collider->cast_to<CollisionObject>(); if (co) { - co->_input_event(ev,result.position,result.normal,result.shape); + + co->_input_event(camera,ev,result.position,result.normal,result.shape); last_object=co; last_id=result.collider_id; new_collider=last_id; @@ -491,6 +499,7 @@ void Viewport::_notification(int p_what) { } } +#endif } } break; @@ -507,6 +516,7 @@ void Viewport::set_rect(const Rect2& p_rect) { if (rect==p_rect) return; rect=p_rect; + _update_rect(); _update_stretch_transform(); @@ -541,7 +551,7 @@ Rect2 Viewport::get_rect() const { void Viewport::_update_listener() { - if (is_inside_scene() && audio_listener && camera) { + if (is_inside_tree() && audio_listener && camera && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible()))) { SpatialSoundServer::get_singleton()->listener_set_space(listener,find_world()->get_sound_space()); } else { SpatialSoundServer::get_singleton()->listener_set_space(listener,RID()); @@ -552,7 +562,7 @@ void Viewport::_update_listener() { void Viewport::_update_listener_2d() { - if (is_inside_scene() && audio_listener_2d) + if (is_inside_tree() && audio_listener && (!get_parent() || (get_parent()->cast_to<Control>() && get_parent()->cast_to<Control>()->is_visible()))) SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,find_world_2d()->get_sound_space()); else SpatialSound2DServer::get_singleton()->listener_set_space(listener_2d,RID()); @@ -731,7 +741,7 @@ void Viewport::_propagate_enter_world(Node *p_node) { if (p_node!=this) { - if (!p_node->is_inside_scene()) //may not have entered scene yet + if (!p_node->is_inside_tree()) //may not have entered scene yet return; Spatial *s = p_node->cast_to<Spatial>(); @@ -760,7 +770,7 @@ void Viewport::_propagate_exit_world(Node *p_node) { if (p_node!=this) { - if (!p_node->is_inside_scene()) //may have exited scene already + if (!p_node->is_inside_tree()) //may have exited scene already return; Spatial *s = p_node->cast_to<Spatial>(); @@ -791,7 +801,7 @@ void Viewport::set_world(const Ref<World>& p_world) { if (world==p_world) return; - if (is_inside_scene()) + if (is_inside_tree()) _propagate_exit_world(this); #ifndef _3D_DISABLED @@ -801,7 +811,7 @@ void Viewport::set_world(const Ref<World>& p_world) { world=p_world; - if (is_inside_scene()) + if (is_inside_tree()) _propagate_enter_world(this); #ifndef _3D_DISABLED @@ -811,7 +821,7 @@ void Viewport::set_world(const Ref<World>& p_world) { //propagate exit - if (is_inside_scene()) { + if (is_inside_tree()) { VisualServer::get_singleton()->viewport_set_scenario(viewport,find_world()->get_scenario()); } @@ -899,12 +909,12 @@ void Viewport::set_as_render_target(bool p_enable){ render_target=p_enable; VS::get_singleton()->viewport_set_as_render_target(viewport,p_enable); - if (is_inside_scene()) { + if (is_inside_tree()) { if (p_enable) - _vp_exit_scene(); + _vp_exit_tree(); else - _vp_enter_scene(); + _vp_enter_tree(); } if (p_enable) { @@ -1023,13 +1033,16 @@ void Viewport::_make_input_local(InputEvent& ev) { Matrix32 ai = get_final_transform().affine_inverse() * _get_input_pre_xform(); Vector2 g = ai.xform(Vector2(ev.mouse_motion.global_x,ev.mouse_motion.global_y)); Vector2 l = ai.xform(Vector2(ev.mouse_motion.x,ev.mouse_motion.y)); - Vector2 r = ai.xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y)); + Vector2 r = ai.basis_xform(Vector2(ev.mouse_motion.relative_x,ev.mouse_motion.relative_y)); + Vector2 s = ai.basis_xform(Vector2(ev.mouse_motion.speed_x,ev.mouse_motion.speed_y)); ev.mouse_motion.x=l.x; ev.mouse_motion.y=l.y; ev.mouse_motion.global_x=g.x; ev.mouse_motion.global_y=g.y; ev.mouse_motion.relative_x=r.x; ev.mouse_motion.relative_y=r.y; + ev.mouse_motion.speed_x=s.x; + ev.mouse_motion.speed_y=s.y; } break; case InputEvent::SCREEN_TOUCH: { @@ -1044,8 +1057,8 @@ void Viewport::_make_input_local(InputEvent& ev) { Matrix32 ai = get_final_transform().affine_inverse() * _get_input_pre_xform(); Vector2 t = ai.xform(Vector2(ev.screen_drag.x,ev.screen_drag.y)); - Vector2 r = ai.xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y)); - Vector2 s = ai.xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y)); + Vector2 r = ai.basis_xform(Vector2(ev.screen_drag.relative_x,ev.screen_drag.relative_y)); + Vector2 s = ai.basis_xform(Vector2(ev.screen_drag.speed_x,ev.screen_drag.speed_y)); ev.screen_drag.x=t.x; ev.screen_drag.y=t.y; ev.screen_drag.relative_x=r.x; @@ -1089,24 +1102,24 @@ void Viewport::_vp_unhandled_input(const InputEvent& p_ev) { void Viewport::input(const InputEvent& p_event) { - ERR_FAIL_COND(!is_inside_scene()); - get_scene()->_call_input_pause(input_group,"_input",p_event); - get_scene()->call_group(SceneMainLoop::GROUP_CALL_REVERSE|SceneMainLoop::GROUP_CALL_REALTIME|SceneMainLoop::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check + ERR_FAIL_COND(!is_inside_tree()); + get_tree()->_call_input_pause(input_group,"_input",p_event); + get_tree()->call_group(SceneTree::GROUP_CALL_REVERSE|SceneTree::GROUP_CALL_REALTIME|SceneTree::GROUP_CALL_MULIILEVEL,gui_input_group,"_gui_input",p_event); //special one for GUI, as controls use their own process check } void Viewport::unhandled_input(const InputEvent& p_event) { - ERR_FAIL_COND(!is_inside_scene()); + ERR_FAIL_COND(!is_inside_tree()); - get_scene()->_call_input_pause(unhandled_input_group,"_unhandled_input",p_event); + get_tree()->_call_input_pause(unhandled_input_group,"_unhandled_input",p_event); //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_input","_unhandled_input",ev); - if (!get_scene()->input_handled && p_event.type==InputEvent::KEY) { - get_scene()->_call_input_pause(unhandled_key_input_group,"_unhandled_key_input",p_event); + if (!get_tree()->input_handled && p_event.type==InputEvent::KEY) { + get_tree()->_call_input_pause(unhandled_key_input_group,"_unhandled_key_input",p_event); //call_group(GROUP_CALL_REVERSE|GROUP_CALL_REALTIME|GROUP_CALL_MULIILEVEL,"unhandled_key_input","_unhandled_key_input",ev); } - if (physics_object_picking && !get_scene()->input_handled) { + if (physics_object_picking && !get_tree()->input_handled) { if (p_event.type==InputEvent::MOUSE_BUTTON || p_event.type==InputEvent::MOUSE_MOTION || p_event.type==InputEvent::SCREEN_DRAG || p_event.type==InputEvent::SCREEN_TOUCH) { physics_picking_events.push_back(p_event); @@ -1121,7 +1134,7 @@ void Viewport::set_use_own_world(bool p_world) { return; - if (is_inside_scene()) + if (is_inside_tree()) _propagate_exit_world(this); #ifndef _3D_DISABLED @@ -1134,7 +1147,7 @@ void Viewport::set_use_own_world(bool p_world) { else own_world=Ref<World>( memnew( World )); - if (is_inside_scene()) + if (is_inside_tree()) _propagate_enter_world(this); #ifndef _3D_DISABLED @@ -1144,7 +1157,7 @@ void Viewport::set_use_own_world(bool p_world) { //propagate exit - if (is_inside_scene()) { + if (is_inside_tree()) { VisualServer::get_singleton()->viewport_set_scenario(viewport,find_world()->get_scenario()); } @@ -1179,6 +1192,21 @@ void Viewport::set_physics_object_picking(bool p_enable) { } + +Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const { + + Matrix32 xf = get_final_transform(); + return xf.xform(p_viewport_coords); + + +} + +Vector2 Viewport::get_camera_rect_size() const { + + return last_vp_rect.size; +} + + bool Viewport::get_physics_object_picking() { diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 5d68438f0d..4bb5735731 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -110,6 +110,7 @@ friend class RenderTargetTexture; Size2 size_override_size; Size2 size_override_margin; + Rect2 last_vp_rect; bool transparent_bg; bool render_target_vflip; @@ -158,8 +159,8 @@ friend class RenderTargetTexture; _FORCE_INLINE_ Matrix32 _get_input_pre_xform() const; - void _vp_enter_scene(); - void _vp_exit_scene(); + void _vp_enter_tree(); + void _vp_exit_tree(); void _vp_input(const InputEvent& p_ev); void _vp_unhandled_input(const InputEvent& p_ev); @@ -229,6 +230,10 @@ public: RenderTargetUpdateMode get_render_target_update_mode() const; Ref<RenderTargetTexture> get_render_target_texture() const; + + Vector2 get_camera_coords(const Vector2& p_viewport_coords) const; + Vector2 get_camera_rect_size() const; + void queue_screen_capture(); Image get_screen_capture() const; diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 2a1cca6a3a..8f28a3116e 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -32,14 +32,13 @@ #include "scene/io/resource_format_image.h" #include "scene/io/resource_format_wav.h" -#include "scene/io/scene_format_script.h" +//#include "scene/io/scene_format_script.h" #include "resources/default_theme/default_theme.h" #include "object_type_db.h" #include "scene/main/canvas_layer.h" #include "scene/main/viewport.h" #include "scene/gui/control.h" #include "scene/gui/texture_progress.h" -#include "scene/gui/empty_control.h" #include "scene/gui/button.h" #include "scene/gui/button_array.h" #include "scene/gui/button_group.h" @@ -75,6 +74,8 @@ #include "scene/gui/split_container.h" #include "scene/gui/video_player.h" #include "scene/gui/reference_frame.h" +#include "scene/gui/graph_node.h" +#include "scene/gui/graph_edit.h" #include "scene/resources/video_stream.h" #include "scene/2d/particles_2d.h" #include "scene/2d/path_2d.h" @@ -100,6 +101,7 @@ #include "scene/2d/sample_player_2d.h" #include "scene/2d/screen_button.h" #include "scene/2d/remote_transform_2d.h" +#include "scene/2d/y_sort.h" #include "scene/2d/position_2d.h" #include "scene/2d/tile_map.h" @@ -119,7 +121,7 @@ #include "scene/resources/scene_preloader.h" #include "scene/main/timer.h" -#include "scene/io/scene_format_object.h" + #include "scene/audio/stream_player.h" #include "scene/audio/event_player.h" #include "scene/audio/sound_room_params.h" @@ -141,7 +143,7 @@ #include "scene/resources/mesh_library.h" -#include "scene/resources/image_path_finder.h" + #include "scene/resources/polygon_path_finder.h" #include "scene/resources/sample.h" @@ -151,6 +153,8 @@ #include "scene/resources/mesh.h" #include "scene/resources/room.h" +#include "scene/resources/shader_graph.h" + #include "scene/resources/world.h" #include "scene/resources/world_2d.h" #include "scene/resources/volume.h" @@ -173,9 +177,8 @@ #ifndef _3D_DISABLED #include "scene/3d/camera.h" -#include "scene/3d/editable_shape.h" + #include "scene/3d/interpolated_camera.h" -#include "scene/3d/follow_camera.h" #include "scene/3d/position_3d.h" #include "scene/3d/test_cube.h" #include "scene/3d/mesh_instance.h" @@ -185,7 +188,7 @@ #include "scene/3d/portal.h" #include "scene/resources/environment.h" #include "scene/3d/physics_body.h" -#include "scene/3d/car_body.h" + #include "scene/3d/vehicle_body.h" #include "scene/3d/body_shape.h" #include "scene/3d/area.h" @@ -203,7 +206,7 @@ #include "scene/3d/collision_polygon.h" #endif -#include "scene/scene_binds.h" + static ResourceFormatLoaderImage *resource_loader_image=NULL; static ResourceFormatLoaderWAV *resource_loader_wav=NULL; @@ -215,15 +218,6 @@ static ResourceFormatLoaderBitMap *resource_loader_bitmap=NULL; #endif static ResourceFormatLoaderTheme *resource_loader_theme=NULL; static ResourceFormatLoaderShader *resource_loader_shader=NULL; -#ifdef OLD_SCENE_FORMAT_ENABLED -static SceneFormatSaverObject *scene_saver_object=NULL; -static SceneFormatLoaderObject *scene_loader_object=NULL; -//static SceneFormatLoaderScript *scene_loader_script=NULL; -#endif - -#ifdef OLD_SCENE_FORMAT_ENABLED -SceneIO *scene_io=NULL; -#endif //static SceneStringNames *string_names; @@ -235,13 +229,6 @@ void register_scene_types() { Node::init_node_hrcr(); -#ifdef OLD_SCENE_FORMAT_ENABLED - ObjectTypeDB::register_type<SceneIO>(); - ObjectTypeDB::register_virtual_type<SceneInteractiveLoader>(); - scene_io = memnew( SceneIO ); - Globals::get_singleton()->add_singleton(Globals::Singleton("SceneIO",scene_io)); -#endif - resource_loader_image = memnew( ResourceFormatLoaderImage ); ResourceLoader::add_resource_format_loader( resource_loader_image ); @@ -262,16 +249,6 @@ void register_scene_types() { resource_loader_shader = memnew( ResourceFormatLoaderShader ); ResourceLoader::add_resource_format_loader( resource_loader_shader ); -#ifdef OLD_SCENE_FORMAT_ENABLED - scene_saver_object=memnew( SceneFormatSaverObject ); - SceneSaver::add_scene_format_saver(scene_saver_object); - - scene_loader_object=memnew( SceneFormatLoaderObject ); - SceneLoader::add_scene_format_loader(scene_loader_object); - -// scene_loader_script=memnew( SceneFormatLoaderScript ); -// SceneLoader::add_scene_format_loader(scene_loader_script); -#endif make_default_theme(); @@ -294,7 +271,8 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init ObjectTypeDB::register_type<Control>(); - ObjectTypeDB::register_type<EmptyControl>(); +// ObjectTypeDB::register_type<EmptyControl>(); + ObjectTypeDB::add_compatibility_type("EmptyControl","Control"); ObjectTypeDB::register_type<Button>(); ObjectTypeDB::register_type<Label>(); ObjectTypeDB::register_type<HScrollBar>(); @@ -329,6 +307,8 @@ void register_scene_types() { ObjectTypeDB::register_virtual_type<SplitContainer>(); ObjectTypeDB::register_type<HSplitContainer>(); ObjectTypeDB::register_type<VSplitContainer>(); + ObjectTypeDB::register_type<GraphNode>(); + ObjectTypeDB::register_type<GraphEdit>(); OS::get_singleton()->yield(); //may take time to init @@ -378,7 +358,6 @@ void register_scene_types() { ObjectTypeDB::register_type<BoneAttachment>(); ObjectTypeDB::register_virtual_type<VisualInstance>(); ObjectTypeDB::register_type<Camera>(); - ObjectTypeDB::register_type<FollowCamera>(); ObjectTypeDB::register_type<InterpolatedCamera>(); ObjectTypeDB::register_type<TestCube>(); ObjectTypeDB::register_type<MeshInstance>(); @@ -404,8 +383,8 @@ void register_scene_types() { ObjectTypeDB::register_type<StaticBody>(); ObjectTypeDB::register_type<RigidBody>(); ObjectTypeDB::register_type<KinematicBody>(); - ObjectTypeDB::register_type<CarBody>(); - ObjectTypeDB::register_type<CarWheel>(); + + ObjectTypeDB::register_type<VehicleBody>(); ObjectTypeDB::register_type<VehicleWheel>(); ObjectTypeDB::register_type<Area>(); @@ -413,8 +392,6 @@ void register_scene_types() { ObjectTypeDB::register_type<CollisionShape>(); ObjectTypeDB::register_type<CollisionPolygon>(); ObjectTypeDB::register_type<RayCast>(); - ObjectTypeDB::register_virtual_type<EditableShape>(); - ObjectTypeDB::register_type<EditableSphere>(); ObjectTypeDB::register_type<MultiMeshInstance>(); ObjectTypeDB::register_type<Room>(); ObjectTypeDB::register_type<Curve3D>(); @@ -423,8 +400,16 @@ void register_scene_types() { ObjectTypeDB::register_type<VisibilityNotifier>(); ObjectTypeDB::register_type<VisibilityEnabler>(); ObjectTypeDB::register_type<BakedLightInstance>(); + ObjectTypeDB::register_type<BakedLightSampler>(); ObjectTypeDB::register_type<WorldEnvironment>(); + ObjectTypeDB::register_virtual_type<Joint>(); + ObjectTypeDB::register_type<PinJoint>(); + ObjectTypeDB::register_type<HingeJoint>(); + ObjectTypeDB::register_type<SliderJoint>(); + ObjectTypeDB::register_type<ConeTwistJoint>(); + ObjectTypeDB::register_type<Generic6DOFJoint>(); + //scenariofx OS::get_singleton()->yield(); //may take time to init @@ -433,6 +418,7 @@ void register_scene_types() { ObjectTypeDB::register_type<SpatialStreamPlayer>(); ObjectTypeDB::register_type<SoundRoomParams>(); + #endif ObjectTypeDB::register_type<MeshLibrary>(); AcceptDialog::set_swap_ok_cancel( GLOBAL_DEF("display/swap_ok_cancel",bool(OS::get_singleton()->get_swap_ok_cancel())) ); @@ -450,12 +436,6 @@ void register_scene_types() { //ObjectTypeDB::register_type<PhysicsJointPin>(); - ObjectTypeDB::register_virtual_type<Joint>(); - ObjectTypeDB::register_type<PinJoint>(); - ObjectTypeDB::register_type<HingeJoint>(); - ObjectTypeDB::register_type<SliderJoint>(); - ObjectTypeDB::register_type<ConeTwistJoint>(); - ObjectTypeDB::register_type<Generic6DOFJoint>(); ObjectTypeDB::register_type<StreamPlayer>(); @@ -491,6 +471,7 @@ void register_scene_types() { ObjectTypeDB::register_type<VisibilityNotifier2D>(); ObjectTypeDB::register_type<VisibilityEnabler2D>(); ObjectTypeDB::register_type<Polygon2D>(); + ObjectTypeDB::register_type<YSort>(); ObjectTypeDB::set_type_enabled("CollisionShape2D",false); ObjectTypeDB::set_type_enabled("CollisionPolygon2D",false); @@ -519,11 +500,16 @@ void register_scene_types() { ObjectTypeDB::register_type<Mesh>(); ObjectTypeDB::register_virtual_type<Material>(); ObjectTypeDB::register_type<FixedMaterial>(); - ObjectTypeDB::register_type<ParticleSystemMaterial>(); - ObjectTypeDB::register_type<UnshadedMaterial>(); ObjectTypeDB::register_type<ShaderMaterial>(); ObjectTypeDB::register_type<RoomBounds>(); - ObjectTypeDB::register_type<Shader>(); + ObjectTypeDB::register_virtual_type<Shader>(); + ObjectTypeDB::register_virtual_type<ShaderGraph>(); + ObjectTypeDB::register_type<MaterialShaderGraph>(); + ObjectTypeDB::register_type<MaterialShader>(); + ObjectTypeDB::register_type<CanvasItemShader>(); + ObjectTypeDB::add_compatibility_type("Shader","MaterialShader"); + ObjectTypeDB::add_compatibility_type("ParticleSystemMaterial","FixedMaterial"); + ObjectTypeDB::add_compatibility_type("UnshadedMaterial","FixedMaterial"); ObjectTypeDB::register_type<MultiMesh>(); ObjectTypeDB::register_type<MeshLibrary>(); @@ -559,7 +545,7 @@ void register_scene_types() { ObjectTypeDB::register_type<StyleBoxFlat>(); ObjectTypeDB::register_type<StyleBoxImageMask>(); ObjectTypeDB::register_type<Theme>(); - ObjectTypeDB::register_type<ImagePathFinder>(); + ObjectTypeDB::register_type<PolygonPathFinder>(); ObjectTypeDB::register_type<BitMap>(); @@ -590,12 +576,8 @@ void register_scene_types() { OS::get_singleton()->yield(); //may take time to init ObjectTypeDB::register_type<PackedScene>(); -#ifdef OLD_SCENE_FORMAT_ENABLED - ObjectTypeDB::register_type<ScenePreloader>(); -#endif - - ObjectTypeDB::register_type<SceneMainLoop>(); + ObjectTypeDB::register_type<SceneTree>(); OS::get_singleton()->yield(); //may take time to init @@ -617,11 +599,5 @@ void unregister_scene_types() { memdelete( resource_loader_theme ); memdelete( resource_loader_shader ); -#ifdef OLD_SCENE_FORMAT_ENABLED - memdelete( scene_saver_object ); - memdelete( scene_loader_object ); -// memdelete( scene_loader_script ); - memdelete( scene_io ); -#endif SceneStringNames::free(); } diff --git a/scene/resources/SCsub b/scene/resources/SCsub index 87bd33e00e..eaa282ae1a 100644 --- a/scene/resources/SCsub +++ b/scene/resources/SCsub @@ -1,6 +1,7 @@ Import('env') env.add_source_files(env.scene_sources,"*.cpp") +env.add_source_files(env.scene_sources,"*.c") Export('env') diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp index 67f45ced2b..80993c7eaf 100644 --- a/scene/resources/animation.cpp +++ b/scene/resources/animation.cpp @@ -1266,7 +1266,7 @@ T Animation::_interpolate( const Vector< TKey<T> >& p_keys, float p_time, Inter } } else { // no loop - + if (idx>=0) { if ((idx+1) < len) { @@ -1716,185 +1716,222 @@ void Animation::clear() { } -void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err) { - ERR_FAIL_INDEX(p_idx,tracks.size()); - ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM); - TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]); - 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 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) { - real_t c = (t1.time-t0.time)/(t2.time-t0.time); - real_t t[3]={-1,-1,-1}; - { //translation + real_t c = (t1.time-t0.time)/(t2.time-t0.time); + real_t t[3]={-1,-1,-1}; - const Vector3 &v0=t0.value.loc; - const Vector3 &v1=t1.value.loc; - const Vector3 &v2=t2.value.loc; + { //translation - if (v0.distance_to(v2)<CMP_EPSILON) { - //0 and 2 are close, let's see if 1 is close - if (v0.distance_to(v1)>CMP_EPSILON) { - //not close, not optimizable - continue; - } + const Vector3 &v0=t0.value.loc; + const Vector3 &v1=t1.value.loc; + const Vector3 &v2=t2.value.loc; - } else { + if (v0.distance_to(v2)<CMP_EPSILON) { + //0 and 2 are close, let's see if 1 is close + if (v0.distance_to(v1)>CMP_EPSILON) { + //not close, not optimizable + return false; + } - Vector3 pd = (v2-v0); - float d0 = pd.dot(v0); - float d1 = pd.dot(v1); - float d2 = pd.dot(v2); - if (d1<d0 || d1>d2) { - continue; //beyond segment range - } + } else { - Vector3 s[2]={ v0, v2 }; - real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1); + Vector3 pd = (v2-v0); + float d0 = pd.dot(v0); + float d1 = pd.dot(v1); + float d2 = pd.dot(v2); + if (d1<d0 || d1>d2) { + return false; + } - if (d>pd.length()*p_alowed_linear_err) { - continue; //beyond allowed error for colinearity - } + Vector3 s[2]={ v0, v2 }; + real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1); - t[0] = (d1-d0)/(d2-d0); + if (d>pd.length()*p_alowed_linear_err) { + return false; //beyond allowed error for colinearity } - } - { //rotation + t[0] = (d1-d0)/(d2-d0); + } + } - const Quat &q0=t0.value.rot; - const Quat &q1=t1.value.rot; - const Quat &q2=t2.value.rot; + { //rotation - //localize both to rotation from q0 + const Quat &q0=t0.value.rot; + const Quat &q1=t1.value.rot; + const Quat &q2=t2.value.rot; - if ((q0-q2).length() < CMP_EPSILON) { + //localize both to rotation from q0 - if ((q0-q1).length() > CMP_EPSILON) - continue; + if ((q0-q2).length() < CMP_EPSILON) { - } else { + if ((q0-q1).length() > CMP_EPSILON) + return false; - Quat r02 = (q0.inverse() * q2).normalized(); - Quat r01 = (q0.inverse() * q1).normalized(); + } else { - Vector3 v02,v01; - real_t a02,a01; - r02.get_axis_and_angle(v02,a02); - r01.get_axis_and_angle(v01,a01); + Quat r02 = (q0.inverse() * q2).normalized(); + Quat r01 = (q0.inverse() * q1).normalized(); - if (v01.dot(v02)<0) { - //make sure both rotations go the same way to compare - v02=-v02; - a02=-a02; - } + Vector3 v02,v01; + real_t a02,a01; - real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI; - if (err_01>p_alowed_angular_err) { - //not rotating in the same axis - continue; - } + r02.get_axis_and_angle(v02,a02); + r01.get_axis_and_angle(v01,a01); - if (a01*a02 < 0 ) { - //not rotating in the same direction - continue; - } + if (Math::abs(a02)>p_max_optimizable_angle) + return false; - real_t tr = a01/a02; - if (tr<0 || tr>1) - continue; //rotating too much or too less + if (v01.dot(v02)<0) { + //make sure both rotations go the same way to compare + v02=-v02; + a02=-a02; + } - t[1]=tr; + real_t err_01 = Math::acos(v01.normalized().dot(v02.normalized()))/Math_PI; + if (err_01>p_alowed_angular_err) { + //not rotating in the same axis + return false; + } + if (a01*a02 < 0 ) { + //not rotating in the same direction + return false; } + real_t tr = a01/a02; + if (tr<0 || tr>1) + return false; //rotating too much or too less + + t[1]=tr; + } - { //scale + } - const Vector3 &v0=t0.value.scale; - const Vector3 &v1=t1.value.scale; - const Vector3 &v2=t2.value.scale; + { //scale - if (v0.distance_to(v2)<CMP_EPSILON) { - //0 and 2 are close, let's see if 1 is close - if (v0.distance_to(v1)>CMP_EPSILON) { - //not close, not optimizable - continue; - } + const Vector3 &v0=t0.value.scale; + const Vector3 &v1=t1.value.scale; + const Vector3 &v2=t2.value.scale; - } else { + if (v0.distance_to(v2)<CMP_EPSILON) { + //0 and 2 are close, let's see if 1 is close + if (v0.distance_to(v1)>CMP_EPSILON) { + //not close, not optimizable + return false; + } - Vector3 pd = (v2-v0); - float d0 = pd.dot(v0); - float d1 = pd.dot(v1); - float d2 = pd.dot(v2); - if (d1<d0 || d1>d2) { - continue; //beyond segment range - } + } else { - Vector3 s[2]={ v0, v2 }; - real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1); + Vector3 pd = (v2-v0); + float d0 = pd.dot(v0); + float d1 = pd.dot(v1); + float d2 = pd.dot(v2); + if (d1<d0 || d1>d2) { + return false; //beyond segment range + } - if (d>pd.length()*p_alowed_linear_err) { - continue; //beyond allowed error for colinearity - } + Vector3 s[2]={ v0, v2 }; + real_t d =Geometry::get_closest_point_to_segment(v1,s).distance_to(v1); - t[2] = (d1-d0)/(d2-d0); + if (d>pd.length()*p_alowed_linear_err) { + return false; //beyond allowed error for colinearity } + + t[2] = (d1-d0)/(d2-d0); } + } - bool erase=false; - if (t[0]==-1 && t[1]==-1 && t[2]==-1) { + bool erase=false; + if (t[0]==-1 && t[1]==-1 && t[2]==-1) { - erase=true; - } else { + erase=true; + } else { - erase=true; - real_t lt=-1; - for(int j=0;j<3;j++) { - //search for t on first, one must be it - if (t[j]!=-1) { - lt=t[j]; //official t - //validate rest - for(int k=j+1;k<3;k++) { - if (t[k]==-1) - continue; - - if (Math::abs(lt-t[k])>p_alowed_linear_err) { - erase=false; - break; - } + erase=true; + real_t lt=-1; + for(int j=0;j<3;j++) { + //search for t on first, one must be it + if (t[j]!=-1) { + lt=t[j]; //official t + //validate rest + for(int k=j+1;k<3;k++) { + if (t[k]==-1) + continue; + + if (Math::abs(lt-t[k])>p_alowed_linear_err) { + erase=false; + break; } - break; } + break; } + } - ERR_CONTINUE( lt==-1 ); + ERR_FAIL_COND_V( lt==-1,false ); - if (erase) { + if (erase) { - if (Math::abs(lt-c)>p_alowed_linear_err) { - //todo, evaluate changing the transition if this fails? - //this could be done as a second pass and would be - //able to optimize more - erase=false; - } else { + if (Math::abs(lt-c)>p_alowed_linear_err) { + //todo, evaluate changing the transition if this fails? + //this could be done as a second pass and would be + //able to optimize more + erase=false; + } else { - //print_line(itos(i)+"because of interp"); - } + //print_line(itos(i)+"because of interp"); } + } + + } + + + return erase; + + +} + +void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,float p_alowed_angular_err,float p_max_optimizable_angle) { + + ERR_FAIL_INDEX(p_idx,tracks.size()); + ERR_FAIL_COND(tracks[p_idx]->type!=TYPE_TRANSFORM); + TransformTrack *tt= static_cast<TransformTrack*>(tracks[p_idx]); + bool prev_erased=false; + TKey<TransformKey> first_erased; + + 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); + + + if (prev_erased && !_transform_track_optimize_key(t0,first_erased,t2,p_alowed_linear_err,p_alowed_angular_err,p_max_optimizable_angle)) { + //avoid error to go beyond first erased key + erase=false; } + if (erase) { + + if (!prev_erased) { + first_erased=t1; + prev_erased=true; + } + tt->transforms.remove(i); i--; + + } else { + prev_erased=false; } @@ -1905,7 +1942,7 @@ void Animation::_transform_track_optimize(int p_idx,float p_alowed_linear_err,fl } -void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err) { +void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err,float p_angle_max) { int total_tt=0; @@ -1913,7 +1950,7 @@ void Animation::optimize(float p_allowed_linear_err,float p_allowed_angular_err) for(int i=0;i<tracks.size();i++) { if (tracks[i]->type==TYPE_TRANSFORM) - _transform_track_optimize(i,p_allowed_linear_err,p_allowed_angular_err); + _transform_track_optimize(i,p_allowed_linear_err,p_allowed_angular_err,p_angle_max); } diff --git a/scene/resources/animation.h b/scene/resources/animation.h index 4c4e2f0275..bf87789e39 100644 --- a/scene/resources/animation.h +++ b/scene/resources/animation.h @@ -204,7 +204,8 @@ private: return idxr; } - void _transform_track_optimize(int p_idx, float p_allowed_err=0.05, float p_alowed_angular_err=0.01); + 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); + 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: @@ -271,7 +272,7 @@ public: void clear(); - void optimize(float p_allowed_linear_err=0.05,float p_allowed_angular_err=0.01); + void optimize(float p_allowed_linear_err=0.05,float p_allowed_angular_err=0.01,float p_max_optimizable_angle=Math_PI*0.125); Animation(); ~Animation(); diff --git a/scene/resources/audio_stream_resampled.cpp b/scene/resources/audio_stream_resampled.cpp index 8e694a6110..bc7bffa9d2 100644 --- a/scene/resources/audio_stream_resampled.cpp +++ b/scene/resources/audio_stream_resampled.cpp @@ -38,15 +38,18 @@ int AudioStreamResampled::get_channel_count() const { template<int C> -void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) { +uint32_t AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) { + + uint32_t read=offset&MIX_FRAC_MASK; for (int i=0;i<p_todo;i++) { offset = (offset + p_increment)&(((1<<(rb_bits+MIX_FRAC_BITS))-1)); + read+=p_increment; uint32_t pos = offset >> MIX_FRAC_BITS; uint32_t frac = offset & MIX_FRAC_MASK; #ifndef FAST_AUDIO - ERR_FAIL_COND(pos>=rb_len); + ERR_FAIL_COND_V(pos>=rb_len,0); #endif uint32_t pos_next = (pos+1)&rb_mask; //printf("rb pos %i\n",pos); @@ -151,7 +154,7 @@ void AudioStreamResampled::_resample(int32_t *p_dest,int p_todo,int32_t p_increm } - rb_read_pos=offset>>MIX_FRAC_BITS; + return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS; } @@ -173,10 +176,10 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) { } else if (rb_read_pos<write_pos_cache) { - rb_todo=write_pos_cache-rb_read_pos-1; + rb_todo=write_pos_cache-rb_read_pos; //-1? } else { - rb_todo=(rb_len-rb_read_pos)+write_pos_cache-1; + rb_todo=(rb_len-rb_read_pos)+write_pos_cache; //-1? } int todo = MIN( ((int64_t(rb_todo)<<MIX_FRAC_BITS)/increment)+1, p_frames ); @@ -220,13 +223,22 @@ bool AudioStreamResampled::mix(int32_t *p_dest, int p_frames) { #endif { + uint32_t read=0; switch(channels) { - case 1: _resample<1>(p_dest,todo,increment); break; - case 2: _resample<2>(p_dest,todo,increment); break; - case 4: _resample<4>(p_dest,todo,increment); break; - case 6: _resample<6>(p_dest,todo,increment); break; + case 1: read=_resample<1>(p_dest,todo,increment); break; + case 2: read=_resample<2>(p_dest,todo,increment); break; + case 4: read=_resample<4>(p_dest,todo,increment); break; + case 6: read=_resample<6>(p_dest,todo,increment); break; } + if (read>rb_todo) + read=rb_todo; + + rb_read_pos = (rb_read_pos+read)&rb_mask; + + + + } return true; diff --git a/scene/resources/audio_stream_resampled.h b/scene/resources/audio_stream_resampled.h index f1e3629ac7..a1b95e81d5 100644 --- a/scene/resources/audio_stream_resampled.h +++ b/scene/resources/audio_stream_resampled.h @@ -57,7 +57,7 @@ class AudioStreamResampled : public AudioStream { template<int C> - void _resample(int32_t *p_dest,int p_todo,int32_t p_increment); + uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment); protected: @@ -97,7 +97,7 @@ protected: _FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; } _FORCE_INLINE_ void write(uint32_t p_frames) { - ERR_FAIL_COND(p_frames > rb_len); + ERR_FAIL_COND(p_frames >= rb_len); switch(channels) { case 1: { diff --git a/scene/resources/baked_light.cpp b/scene/resources/baked_light.cpp index 647c8df5d4..226edec9ae 100644 --- a/scene/resources/baked_light.cpp +++ b/scene/resources/baked_light.cpp @@ -23,6 +23,27 @@ DVector<uint8_t> BakedLight::get_octree() const { return VS::get_singleton()->baked_light_get_octree(baked_light); } +void BakedLight::set_light(const DVector<uint8_t>& p_light) { + + VS::get_singleton()->baked_light_set_light(baked_light,p_light); +} + +DVector<uint8_t> BakedLight::get_light() const { + + return VS::get_singleton()->baked_light_get_light(baked_light); +} + + +void BakedLight::set_sampler_octree(const DVector<int>& p_sampler_octree) { + + VS::get_singleton()->baked_light_set_sampler_octree(baked_light,p_sampler_octree); +} + +DVector<int> BakedLight::get_sampler_octree() const { + + return VS::get_singleton()->baked_light_get_sampler_octree(baked_light); +} + @@ -199,6 +220,43 @@ float BakedLight::get_normal_damp() const { return normal_damp; } +void BakedLight::set_tint(float p_margin) { + tint=p_margin; +} + +float BakedLight::get_tint() const { + + return tint; +} + +void BakedLight::set_saturation(float p_margin) { + saturation=p_margin; +} + +float BakedLight::get_saturation() const { + + return saturation; +} + +void BakedLight::set_ao_radius(float p_ao_radius) { + ao_radius=p_ao_radius; +} + +float BakedLight::get_ao_radius() const { + return ao_radius; +} + +void BakedLight::set_ao_strength(float p_ao_strength) { + + ao_strength=p_ao_strength; +} + +float BakedLight::get_ao_strength() const { + + return ao_strength; +} + + void BakedLight::set_energy_multiplier(float p_multiplier){ energy_multiply=p_multiplier; @@ -329,6 +387,13 @@ void BakedLight::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_octree","octree"),&BakedLight::set_octree); ObjectTypeDB::bind_method(_MD("get_octree"),&BakedLight::get_octree); + ObjectTypeDB::bind_method(_MD("set_light","light"),&BakedLight::set_light); + ObjectTypeDB::bind_method(_MD("get_light"),&BakedLight::get_light); + + ObjectTypeDB::bind_method(_MD("set_sampler_octree","sampler_octree"),&BakedLight::set_sampler_octree); + ObjectTypeDB::bind_method(_MD("get_sampler_octree"),&BakedLight::get_sampler_octree); + + ObjectTypeDB::bind_method(_MD("add_lightmap","texture:Texture","gen_size"),&BakedLight::add_lightmap); ObjectTypeDB::bind_method(_MD("erase_lightmap","id"),&BakedLight::erase_lightmap); ObjectTypeDB::bind_method(_MD("clear_lightmaps"),&BakedLight::clear_lightmaps); @@ -357,6 +422,18 @@ void BakedLight::_bind_methods(){ ObjectTypeDB::bind_method(_MD("set_normal_damp","normal_damp"),&BakedLight::set_normal_damp); ObjectTypeDB::bind_method(_MD("get_normal_damp"),&BakedLight::get_normal_damp); + ObjectTypeDB::bind_method(_MD("set_tint","tint"),&BakedLight::set_tint); + ObjectTypeDB::bind_method(_MD("get_tint"),&BakedLight::get_tint); + + ObjectTypeDB::bind_method(_MD("set_saturation","saturation"),&BakedLight::set_saturation); + ObjectTypeDB::bind_method(_MD("get_saturation"),&BakedLight::get_saturation); + + ObjectTypeDB::bind_method(_MD("set_ao_radius","ao_radius"),&BakedLight::set_ao_radius); + ObjectTypeDB::bind_method(_MD("get_ao_radius"),&BakedLight::get_ao_radius); + + ObjectTypeDB::bind_method(_MD("set_ao_strength","ao_strength"),&BakedLight::set_ao_strength); + ObjectTypeDB::bind_method(_MD("get_ao_strength"),&BakedLight::get_ao_strength); + ObjectTypeDB::bind_method(_MD("set_format","format"),&BakedLight::set_format); ObjectTypeDB::bind_method(_MD("get_format"),&BakedLight::get_format); @@ -384,17 +461,24 @@ void BakedLight::_bind_methods(){ ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/plot_size",PROPERTY_HINT_RANGE,"1.0,16.0,0.01"),_SCS("set_plot_size"),_SCS("get_plot_size")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/energy_mult",PROPERTY_HINT_RANGE,"0.01,4096.0,0.01"),_SCS("set_energy_multiplier"),_SCS("get_energy_multiplier")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/gamma_adjust",PROPERTY_HINT_EXP_EASING),_SCS("set_gamma_adjust"),_SCS("get_gamma_adjust")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"baking/saturation",PROPERTY_HINT_RANGE,"0,8,0.01"),_SCS("set_saturation"),_SCS("get_saturation")); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/diffuse"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_DIFFUSE); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/specular"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_SPECULAR); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/translucent"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_TRANSLUCENT); ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/conserve_energy"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_CONSERVE_ENERGY); + ADD_PROPERTYI( PropertyInfo(Variant::BOOL,"baking_flags/linear_color"),_SCS("set_bake_flag"),_SCS("get_bake_flag"),BAKE_LINEAR_COLOR); ADD_PROPERTY( PropertyInfo(Variant::BOOL,"lightmap/use_only_uv2"),_SCS("set_transfer_lightmaps_only_to_uv2"),_SCS("get_transfer_lightmaps_only_to_uv2")); ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_octree"),_SCS("get_octree")); + ADD_PROPERTY( PropertyInfo(Variant::RAW_ARRAY,"light",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_light"),_SCS("get_light")); + ADD_PROPERTY( PropertyInfo(Variant::INT_ARRAY,"sampler_octree",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("set_sampler_octree"),_SCS("get_sampler_octree")); ADD_PROPERTY( PropertyInfo(Variant::ARRAY,"lightmaps",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR),_SCS("_set_lightmap_data"),_SCS("_get_lightmap_data")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/cell_margin",PROPERTY_HINT_RANGE,"0.01,0.8,0.01"),_SCS("set_cell_extra_margin"),_SCS("get_cell_extra_margin")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/edge_damp",PROPERTY_HINT_RANGE,"0.0,8.0,0.1"),_SCS("set_edge_damp"),_SCS("get_edge_damp")); ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/normal_damp",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_normal_damp"),_SCS("get_normal_damp")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/light_tint",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_tint"),_SCS("get_tint")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_radius",PROPERTY_HINT_RANGE,"0.0,16.0,0.01"),_SCS("set_ao_radius"),_SCS("get_ao_radius")); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"advanced/ao_strength",PROPERTY_HINT_RANGE,"0.0,1.0,0.01"),_SCS("set_ao_strength"),_SCS("get_ao_strength")); BIND_CONSTANT( MODE_OCTREE ); BIND_CONSTANT( MODE_LIGHTMAPS ); @@ -415,18 +499,24 @@ BakedLight::BakedLight() { lattice_subdiv=4; plot_size=2.5; bounces=1; - energy_multiply=1.0; - gamma_adjust=1.0; + energy_multiply=2.0; + gamma_adjust=0.7; cell_extra_margin=0.05; edge_damp=0.0; normal_damp=0.0; + saturation=1; + tint=0.0; + ao_radius=2.5; + ao_strength=0.7; format=FORMAT_RGB; transfer_only_uv2=false; + flags[BAKE_DIFFUSE]=true; flags[BAKE_SPECULAR]=false; flags[BAKE_TRANSLUCENT]=true; flags[BAKE_CONSERVE_ENERGY]=false; + flags[BAKE_LINEAR_COLOR]=false; mode=MODE_OCTREE; baked_light=VS::get_singleton()->baked_light_create(); diff --git a/scene/resources/baked_light.h b/scene/resources/baked_light.h index 57ed7d7aee..41e1e5f9e0 100644 --- a/scene/resources/baked_light.h +++ b/scene/resources/baked_light.h @@ -26,6 +26,7 @@ public: BAKE_SPECULAR, BAKE_TRANSLUCENT, BAKE_CONSERVE_ENERGY, + BAKE_LINEAR_COLOR, BAKE_MAX }; @@ -50,6 +51,10 @@ private: float cell_extra_margin; float edge_damp; float normal_damp; + float tint; + float ao_radius; + float ao_strength; + float saturation; int bounces; bool transfer_only_uv2; Format format; @@ -99,6 +104,18 @@ public: void set_normal_damp(float p_margin); float get_normal_damp() const; + void set_tint(float p_margin); + float get_tint() const; + + void set_saturation(float p_saturation); + float get_saturation() const; + + void set_ao_radius(float p_ao_radius); + float get_ao_radius() const; + + void set_ao_strength(float p_ao_strength); + float get_ao_strength() const; + void set_bake_flag(BakeFlags p_flags,bool p_enable); bool get_bake_flag(BakeFlags p_flags) const; @@ -114,6 +131,14 @@ public: void set_octree(const DVector<uint8_t>& p_octree); DVector<uint8_t> get_octree() const; + void set_light(const DVector<uint8_t>& p_light); + DVector<uint8_t> get_light() const; + + void set_sampler_octree(const DVector<int>& p_sampler_octree); + DVector<int> get_sampler_octree() const; + + + void add_lightmap(const Ref<Texture> &p_texture,Size2 p_gen_size=Size2(256,256)); void set_lightmap_gen_size(int p_idx,const Size2& p_size); Size2 get_lightmap_gen_size(int p_idx) const; diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp index 056be87e72..d6a9db690b 100644 --- a/scene/resources/circle_shape_2d.cpp +++ b/scene/resources/circle_shape_2d.cpp @@ -54,9 +54,7 @@ void CircleShape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_radius","radius"),&CircleShape2D::set_radius); ObjectTypeDB::bind_method(_MD("get_radius"),&CircleShape2D::get_radius); - - - ADD_PROPERTY( PropertyInfo(Variant::REAL,"radius"),_SCS("set_radius"),_SCS("get_radius") ); + ADD_PROPERTY( PropertyInfo(Variant::REAL,"radius",PROPERTY_HINT_RANGE,"0.01,16384,0.5"),_SCS("set_radius"),_SCS("get_radius") ); } diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp index ae2c07ff56..6c27ffc6d9 100644 --- a/scene/resources/curve.cpp +++ b/scene/resources/curve.cpp @@ -134,7 +134,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const { Vector2 Curve2D::interpolatef(real_t p_findex) const { - if (p_findex>0) + if (p_findex<0) p_findex=0; else if (p_findex>=points.size()) p_findex=points.size(); @@ -485,7 +485,7 @@ Vector2 Curve2D::interpolate(int p_index, float p_offset) const { Vector2 Curve2D::interpolatef(real_t p_findex) const { - if (p_findex>0) + if (p_findex<0) p_findex=0; else if (p_findex>=points.size()) p_findex=points.size(); @@ -956,7 +956,7 @@ Vector3 Curve3D::interpolate(int p_index, float p_offset) const { Vector3 Curve3D::interpolatef(real_t p_findex) const { - if (p_findex>0) + if (p_findex<0) p_findex=0; else if (p_findex>=points.size()) p_findex=points.size(); diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp index d10bb37f60..e7f0d9b1f5 100644 --- a/scene/resources/default_theme/default_theme.cpp +++ b/scene/resources/default_theme/default_theme.cpp @@ -65,7 +65,7 @@ static Ref<Texture> make_icon(T p_src) { Ref<ImageTexture> texture( memnew( ImageTexture ) ); - texture->create_from_image( Image(p_src) ); + texture->create_from_image( Image(p_src),ImageTexture::FLAG_FILTER ); return texture; } @@ -331,6 +331,7 @@ void make_default_theme() { t->set_color("current_line_color","TextEdit", Color(0.3,0.5,0.8,0.15) ); t->set_color("cursor_color","TextEdit", control_font_color ); t->set_color("symbol_color","TextEdit", control_font_color_hover ); + t->set_color("brace_mismatch_color","TextEdit", Color(1,0.2,0.2) ); t->set_constant("line_spacing","TextEdit",1 ); t->set_stylebox("scroll","HScrollBar", make_stylebox( hscroll_bg_png,3,3,3,3,0,0,0,0) ); @@ -415,7 +416,21 @@ void make_default_theme() { t->set_color("font_color_hover","PopupMenu", control_font_color ); t->set_constant("hseparation","PopupMenu",2); t->set_constant("vseparation","PopupMenu",1); - + + Ref<StyleBoxTexture> graphsb = make_stylebox(graph_node_png,6,24,6,5,16,24,16,5); + //graphsb->set_expand_margin_size(MARGIN_LEFT,10); + //graphsb->set_expand_margin_size(MARGIN_RIGHT,10); + t->set_stylebox("frame","GraphNode", graphsb ); + t->set_constant("separation","GraphNode", 1 ); + t->set_icon("port","GraphNode", make_icon( graph_port_png ) ); + t->set_icon("close","GraphNode", make_icon( graph_node_close_png ) ); + t->set_font("title_font","GraphNode", default_font ); + t->set_color("title_color","GraphNode", Color(0,0,0,1)); + t->set_constant("title_offset","GraphNode", 18); + t->set_constant("close_offset","GraphNode", 18); + t->set_constant("port_offset","GraphNode", 3); + + t->set_stylebox("bg","Tree", make_stylebox( tree_bg_png,4,4,4,5,3,3,3,3) ); t->set_stylebox("bg_focus","Tree", focus ); Ref<StyleBoxTexture> tree_selected = make_stylebox( selection_png,4,4,4,4); diff --git a/scene/resources/default_theme/graph_node.png b/scene/resources/default_theme/graph_node.png Binary files differnew file mode 100644 index 0000000000..3adccf2c3b --- /dev/null +++ b/scene/resources/default_theme/graph_node.png diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png Binary files differnew file mode 100644 index 0000000000..ea5b510418 --- /dev/null +++ b/scene/resources/default_theme/graph_node_close.png diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png Binary files differnew file mode 100644 index 0000000000..92f425f977 --- /dev/null +++ b/scene/resources/default_theme/graph_port.png diff --git a/scene/resources/default_theme/theme_data.h b/scene/resources/default_theme/theme_data.h index 9cef0265ee..a0f3dcd988 100644 --- a/scene/resources/default_theme/theme_data.h +++ b/scene/resources/default_theme/theme_data.h @@ -99,6 +99,21 @@ static const unsigned char full_panel_bg_png[]={ }; +static const unsigned char graph_node_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x10,0x0,0x0,0x0,0x40,0x8,0x6,0x0,0x0,0x0,0x13,0x7d,0xf7,0x96,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,0xc,0x14,0x10,0x3,0x2e,0x15,0xb6,0x7,0x4a,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,0x6a,0x49,0x44,0x41,0x54,0x58,0xc3,0xed,0x97,0xbb,0x6e,0x13,0x51,0x10,0x86,0xbf,0xf1,0x2e,0xb1,0x83,0x85,0x63,0x5,0x10,0xe2,0x22,0xa5,0x0,0x1a,0x24,0x90,0x22,0x9e,0x81,0x2,0xd1,0x53,0xf1,0x2,0x20,0xa,0x1a,0xa,0xa0,0x44,0xd0,0xd0,0x20,0x81,0xe0,0x5,0xa8,0xe8,0x11,0x5,0xcf,0x80,0x22,0x81,0x42,0x3,0x14,0x91,0xb8,0x4,0x85,0x58,0x8e,0x21,0x78,0xd7,0xd9,0x73,0x86,0xe2,0x9c,0xdd,0xec,0xae,0xd7,0xce,0x85,0xe,0xed,0x34,0xbb,0x3a,0x3e,0xf3,0xcd,0xcc,0x3f,0x63,0x69,0x47,0xd8,0x36,0x1,0x1a,0x40,0xe0,0x9f,0x42,0xd1,0x14,0xb0,0x80,0xf1,0x4f,0x25,0x77,0xa9,0x1,0x1c,0x4,0xe6,0x81,0xa3,0x40,0x7,0x38,0x50,0x2,0x6c,0x1,0x3,0x60,0xd,0xe8,0x1,0x7f,0x0,0x9b,0x46,0x6d,0x3,0x67,0xe6,0xe,0x75,0xaf,0xb7,0x9a,0xad,0xcb,0x33,0x33,0xcd,0x53,0x54,0xd8,0x68,0x14,0x7f,0x89,0xe2,0xe8,0xf5,0xc6,0xaf,0xfe,0x73,0xe0,0x13,0xb0,0x29,0x3e,0xd2,0xc2,0x7c,0xf7,0xf0,0xe3,0xd3,0xb,0x67,0xaf,0x3c,0xb8,0xfb,0x88,0xd9,0x4e,0xab,0xca,0x9f,0xe1,0x20,0xe2,0xde,0xc3,0xdb,0x7c,0x5e,0xf9,0xf8,0xaa,0xd7,0x5f,0xbf,0x5,0xac,0x8,0xd0,0x2,0x16,0x8f,0x1f,0x3b,0xf9,0xe6,0xc5,0xb3,0x97,0xed,0x24,0xb1,0x24,0xa3,0xa4,0x12,0x10,0xce,0x84,0x84,0x61,0x83,0x6b,0x37,0xae,0x6e,0x7e,0xff,0xf1,0xf5,0x12,0xb0,0x14,0x7a,0x1d,0xda,0x61,0x10,0xb6,0x87,0xbf,0x63,0x10,0x75,0x47,0xa,0x2a,0x79,0x85,0x95,0x51,0xbc,0xc5,0x28,0x86,0x30,0x8,0xdb,0xbe,0x6c,0x49,0x1,0x1,0x80,0x51,0xeb,0xfc,0x9d,0xc0,0x4e,0x6b,0xf,0xd1,0xfc,0xb9,0xb3,0x20,0x5,0x68,0xfa,0x8b,0x5a,0x8b,0xaa,0x80,0x28,0x82,0xa0,0x28,0xa2,0x92,0x73,0xd3,0xb1,0xde,0x86,0x85,0x46,0x5b,0x45,0x51,0x50,0x45,0xc4,0x95,0x61,0x53,0x27,0x71,0x61,0x74,0x1a,0xc0,0xaa,0xcd,0x6e,0xa8,0x64,0x2f,0xee,0x5d,0x29,0x8a,0x32,0x39,0x3,0x5f,0xb6,0x2f,0x4c,0x45,0x73,0x5a,0xd8,0x31,0x48,0x1,0x60,0xac,0x2d,0xf1,0x5,0x51,0x75,0x45,0x68,0x5a,0xbf,0x4e,0xcf,0x60,0xfb,0x82,0x2b,0x5a,0x73,0x4e,0xb6,0xe2,0xf,0x52,0x2,0xd8,0x82,0xe2,0x14,0x50,0x54,0xc4,0x2f,0x8b,0x68,0xad,0x1f,0x99,0x54,0x79,0x41,0xdd,0x0,0xf8,0xb6,0x82,0x88,0x4e,0xeb,0x82,0x66,0x89,0xaa,0x3b,0xc8,0x52,0x48,0x41,0x56,0x76,0xcc,0x60,0x7b,0x74,0x75,0xac,0x1a,0x49,0x47,0x72,0x72,0x6,0xe2,0xe7,0x56,0x45,0xfd,0x5d,0xc9,0x44,0x28,0x40,0x2b,0x45,0x34,0xea,0x7,0xa8,0x14,0xc9,0x92,0x75,0x64,0x7,0x11,0x8d,0x8f,0x98,0x9b,0x87,0xf2,0xf4,0x4d,0xd5,0x40,0xd5,0xc9,0x97,0xf,0xa3,0x5a,0x74,0x9c,0x36,0x89,0xf7,0x9f,0xdc,0x61,0xaf,0x96,0x1,0x92,0x2d,0xc3,0xe2,0xf9,0x8b,0xbb,0x72,0x5a,0x7a,0xff,0xb6,0x3a,0x83,0x8d,0x41,0x7f,0xcf,0x19,0x34,0xf8,0x47,0xab,0x1,0x35,0xa0,0x6,0xd4,0x80,0x1a,0x50,0x3,0x6a,0xc0,0x7f,0x9,0x90,0x8a,0x4f,0xe0,0x3d,0x67,0x60,0xf7,0xe1,0x6b,0x53,0x80,0x5,0x22,0x63,0x4c,0x6c,0x93,0x5d,0x78,0x25,0x60,0x8c,0x89,0x81,0x8,0xb0,0xd,0xbf,0xca,0xae,0x47,0xf1,0x70,0x79,0xad,0xb7,0xca,0x34,0x88,0x4d,0x60,0xad,0xb7,0x4a,0x14,0xf,0x97,0x81,0x75,0xc0,0xa4,0x9b,0xeb,0x1c,0x70,0xa1,0xd3,0xee,0x3e,0x6d,0x35,0x67,0xcf,0x5,0x41,0x50,0x29,0xae,0x31,0xc6,0x46,0xf1,0xf0,0xc3,0x60,0xb3,0x7f,0x13,0x78,0x7,0x6c,0x48,0x6e,0x85,0xeb,0x0,0x27,0x80,0x23,0x40,0x73,0xc2,0xf2,0x1d,0x3,0x3f,0x81,0x6f,0x7e,0x8f,0x36,0x52,0x12,0x34,0x4c,0xf7,0xc1,0x9,0x55,0xa8,0x2f,0x39,0xd9,0xa7,0xf0,0xe3,0xf6,0x17,0x4c,0x97,0x1d,0x24,0x5b,0x8,0x8b,0x95,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + +static const unsigned char graph_node_close_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xc,0x0,0x0,0x0,0xc,0x8,0x6,0x0,0x0,0x0,0x56,0x75,0x5c,0xe7,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,0xc,0x15,0x14,0x15,0x39,0x35,0x48,0xf8,0xe3,0x0,0x0,0x0,0x80,0x49,0x44,0x41,0x54,0x28,0xcf,0xa5,0xd1,0xb1,0xa,0xc2,0x40,0x10,0x84,0xe1,0x4f,0xe5,0x30,0xad,0x9d,0xb5,0x60,0xeb,0x3,0x88,0x2f,0x6d,0xfa,0xb4,0x29,0x83,0xbd,0xb5,0xb5,0x9d,0x68,0x15,0x9b,0x3d,0xb9,0x4,0x11,0xe,0x7,0xb6,0xd9,0xfd,0x67,0xb9,0xb9,0xa5,0x52,0xab,0xa8,0x13,0xb6,0x78,0xe0,0x39,0x63,0x36,0x38,0x60,0x87,0x1b,0x34,0xb8,0x60,0xc4,0x19,0xa9,0x80,0x53,0xf4,0xc6,0x60,0x9a,0x72,0xd0,0xc6,0xa0,0x2b,0xc,0x5d,0xf4,0xda,0xd9,0xa2,0x8f,0x29,0x3,0x43,0x54,0x5e,0x90,0x7e,0xe5,0xca,0x60,0x36,0x4e,0xb4,0xf4,0x87,0xaa,0x9e,0x54,0x15,0xba,0xea,0x5b,0x17,0x71,0xb8,0x23,0x5e,0xb8,0xe2,0xfe,0xe5,0x70,0x7b,0xac,0xd1,0x57,0x7,0x7d,0x3,0x51,0x8f,0x29,0x6b,0x3c,0x49,0x28,0x81,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + +static const unsigned char graph_port_png[]={ +0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0xa,0x0,0x0,0x0,0xa,0x8,0x6,0x0,0x0,0x0,0x8d,0x32,0xcf,0xbd,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x0,0x0,0x0,0x0,0x0,0xf9,0x43,0xbb,0x7f,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,0xc,0x14,0x17,0x20,0x3,0xeb,0x8f,0x3a,0xdb,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,0x1,0x65,0x49,0x44,0x41,0x54,0x18,0xd3,0x4d,0xd0,0x4f,0x6b,0xda,0x70,0x1c,0x7,0xe0,0xcf,0x37,0x7f,0x7e,0x49,0x66,0xd2,0x64,0x61,0x5,0x61,0x76,0x47,0xf1,0xa4,0x2d,0xdb,0x75,0x5,0x11,0x84,0xb0,0x5e,0xeb,0xd9,0xeb,0xf4,0x6d,0xec,0x2d,0xf8,0x26,0xb6,0x77,0xe0,0x45,0xba,0xa3,0x6c,0xa0,0x3b,0xad,0x39,0xb6,0x36,0x8,0x1b,0x4b,0x32,0xd2,0xc6,0x6c,0x9a,0x4f,0x4f,0x85,0x3e,0x2f,0xe1,0x11,0x0,0x20,0x29,0xd3,0xe9,0xd4,0xda,0x6e,0xb7,0x23,0xdf,0xf7,0xbb,0x0,0x90,0xe7,0xf9,0x8f,0x66,0xb3,0xf9,0x79,0x36,0x9b,0x55,0x22,0x42,0x83,0xa4,0x44,0x51,0xf4,0xea,0xe2,0xe2,0xc3,0xf7,0xf1,0x78,0xdc,0xa,0x82,0x40,0x8,0x20,0xcf,0x32,0x2e,0x97,0xcb,0x4f,0x51,0x14,0xbd,0x25,0xf9,0x5b,0x26,0x93,0x89,0xdd,0xe9,0x74,0xe2,0xf7,0xe7,0xe7,0x27,0x59,0xfa,0x87,0x65,0xb9,0x13,0x0,0xb0,0x1d,0x9b,0xe1,0xcb,0x50,0xbe,0x5e,0x5d,0xdd,0xfe,0xbc,0xbe,0x6e,0x6b,0x49,0x92,0x8c,0x4e,0x7b,0xa7,0xad,0xbf,0x79,0x4e,0xd3,0x54,0x12,0x86,0x21,0xc2,0x30,0x84,0x32,0x95,0xe4,0x79,0xc6,0xde,0xd9,0x59,0x2b,0x49,0xee,0x46,0x86,0xeb,0xba,0x5d,0xfb,0x85,0x23,0x87,0xfd,0x1e,0xb6,0xed,0x40,0xd7,0x35,0x0,0x40,0x7d,0x38,0xa0,0xdc,0xed,0x44,0x37,0x74,0xb8,0xae,0xd7,0x35,0x48,0x62,0xff,0xff,0x1f,0xfc,0x20,0x80,0xae,0xe9,0x78,0x42,0x0,0xca,0xb2,0x90,0x65,0x19,0x58,0xd7,0xd0,0x8a,0xa2,0x58,0xa7,0x69,0x56,0x6b,0xa2,0x51,0x29,0x5,0xcb,0x52,0xb0,0x94,0x5,0x4b,0x29,0x88,0x8,0xd3,0x34,0xad,0x8b,0xfb,0x62,0xad,0xf,0x6,0x83,0xb8,0xaa,0xaa,0xb1,0xe7,0x79,0xbe,0x77,0x74,0x44,0xb7,0xe1,0x89,0x69,0x1a,0x28,0xcb,0x92,0x9b,0xcd,0x46,0x56,0xab,0xd5,0x86,0xe4,0x47,0x21,0x29,0xc3,0xe1,0xf0,0xb8,0xdf,0xef,0x7f,0x6b,0xb7,0xdb,0xaf,0x1b,0x8d,0x86,0x46,0x10,0xf,0xf7,0xf,0x75,0x1c,0xc7,0x77,0x8b,0xc5,0xe2,0xdd,0x7c,0x3e,0xff,0x25,0xcf,0xc3,0x6f,0x6e,0x6f,0x2e,0x1d,0xdb,0xe9,0x9,0x80,0xb2,0x2a,0xd7,0x27,0xad,0x37,0x5f,0x9e,0xc2,0x1f,0x1,0x3a,0xe6,0xa5,0x7b,0xef,0xf2,0xf3,0xcd,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 +}; + + static const unsigned char hscroll_bg_png[]={ 0x89,0x50,0x4e,0x47,0xd,0xa,0x1a,0xa,0x0,0x0,0x0,0xd,0x49,0x48,0x44,0x52,0x0,0x0,0x0,0x8,0x0,0x0,0x0,0x8,0x8,0x6,0x0,0x0,0x0,0xc4,0xf,0xbe,0x8b,0x0,0x0,0x0,0x6,0x62,0x4b,0x47,0x44,0x0,0x49,0x0,0x42,0x0,0x4e,0x4e,0xda,0xb4,0x7e,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,0xdd,0x9,0x1b,0x12,0x30,0x1c,0x3c,0x99,0xa,0x1c,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,0x53,0x49,0x44,0x41,0x54,0x18,0xd3,0x7d,0x8f,0xc9,0xd,0x80,0x20,0x0,0xc0,0xca,0x21,0xe8,0x5f,0x12,0x89,0x84,0xfd,0x5c,0x48,0x26,0x34,0x3e,0x74,0x2,0xa2,0xe8,0x2,0x40,0xbf,0xed,0xa7,0xc2,0xbb,0xb0,0x3,0x1b,0x75,0x92,0xf0,0x2e,0x7c,0x46,0x9b,0xaa,0xcd,0x4f,0x46,0x3,0x8c,0x76,0xea,0x7,0x4a,0x29,0x5a,0x68,0x0,0x29,0x65,0x3f,0x30,0x83,0xed,0x6,0xe9,0xbc,0x8e,0xf6,0x45,0x79,0xb,0xc0,0x5c,0xb3,0xeb,0x12,0xef,0x1f,0xc6,0x6f,0x12,0x2,0xa,0xbd,0xc9,0x5d,0x0,0x0,0x0,0x0,0x49,0x45,0x4e,0x44,0xae,0x42,0x60,0x82 }; diff --git a/scene/resources/image_path_finder.cpp b/scene/resources/image_path_finder.cpp deleted file mode 100644 index 1a7758789c..0000000000 --- a/scene/resources/image_path_finder.cpp +++ /dev/null @@ -1,427 +0,0 @@ -/*************************************************************************/ -/* image_path_finder.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "image_path_finder.h"
-
-
-void ImagePathFinder::_unlock() {
-
- lock=DVector<Cell>::Write();
- cells=NULL;
-
-}
-
-void ImagePathFinder::_lock() {
-
- lock = cell_data.write();
- cells=lock.ptr();
-
-}
-
-
-bool ImagePathFinder::_can_go_straigth(const Point2& p_from, const Point2& p_to) const {
-
- int x1=p_from.x;
- int y1=p_from.y;
- int x2=p_to.x;
- int y2=p_to.y;
-
-#define _TEST_VALID \
- {\
- uint32_t ofs=drawy*width+drawx;\
- if (cells[ofs].solid) {\
- if (!((drawx>0 && cells[ofs-1].visited) ||\
- (drawx<width-1 && cells[ofs+1].visited) ||\
- (drawy>0 && cells[ofs-width].visited) ||\
- (drawy<height-1 && cells[ofs+width].visited))) {\
- return false;\
- }\
- }\
- }\
-
-
- int n, deltax, deltay, sgndeltax, sgndeltay, deltaxabs, deltayabs, x, y, drawx, drawy;
- deltax = x2 - x1;
- deltay = y2 - y1;
- deltaxabs = ABS(deltax);
- deltayabs = ABS(deltay);
- sgndeltax = SGN(deltax);
- sgndeltay = SGN(deltay);
- x = deltayabs >> 1;
- y = deltaxabs >> 1;
- drawx = x1;
- drawy = y1;
- int pc=0;
-
- _TEST_VALID
-
- if(deltaxabs >= deltayabs) {
- for(n = 0; n < deltaxabs; n++) {
- y += deltayabs;
- if(y >= deltaxabs){
- y -= deltaxabs;
- drawy += sgndeltay;
- }
- drawx += sgndeltax;
- _TEST_VALID
- }
- } else {
- for(n = 0; n < deltayabs; n++) {
- x += deltaxabs;
- if(x >= deltayabs) {
- x -= deltayabs;
- drawx += sgndeltax;
- }
- drawy += sgndeltay;
- _TEST_VALID
- }
- }
- return true;
-
-
-}
-
-bool ImagePathFinder::_is_linear_path(const Point2& p_from, const Point2& p_to) {
-
- int x1=p_from.x;
- int y1=p_from.y;
- int x2=p_to.x;
- int y2=p_to.y;
-
-#define _TEST_CELL \
- if (cells[drawy*width+drawx].solid)\
- return false;
-
-
- int n, deltax, deltay, sgndeltax, sgndeltay, deltaxabs, deltayabs, x, y, drawx, drawy;
- deltax = x2 - x1;
- deltay = y2 - y1;
- deltaxabs = ABS(deltax);
- deltayabs = ABS(deltay);
- sgndeltax = SGN(deltax);
- sgndeltay = SGN(deltay);
- x = deltayabs >> 1;
- y = deltaxabs >> 1;
- drawx = x1;
- drawy = y1;
- int pc=0;
-
- _TEST_CELL
-
- if(deltaxabs >= deltayabs) {
- for(n = 0; n < deltaxabs; n++) {
- y += deltayabs;
- if(y >= deltaxabs){
- y -= deltaxabs;
- drawy += sgndeltay;
- }
- drawx += sgndeltax;
- _TEST_CELL
- }
- } else {
- for(n = 0; n < deltayabs; n++) {
- x += deltaxabs;
- if(x >= deltayabs) {
- x -= deltayabs;
- drawx += sgndeltax;
- }
- drawy += sgndeltay;
- _TEST_CELL
- }
- }
- return true;
-}
-
-
-DVector<Point2> ImagePathFinder::find_path(const Point2& p_from, const Point2& p_to,bool p_optimize) {
-
-
- Point2i from=p_from;
- Point2i to=p_to;
-
- ERR_FAIL_COND_V(from.x < 0,DVector<Point2>());
- ERR_FAIL_COND_V(from.y < 0,DVector<Point2>());
- ERR_FAIL_COND_V(from.x >=width,DVector<Point2>());
- ERR_FAIL_COND_V(from.y >=height,DVector<Point2>());
- ERR_FAIL_COND_V(to.x < 0,DVector<Point2>());
- ERR_FAIL_COND_V(to.y < 0,DVector<Point2>());
- ERR_FAIL_COND_V(to.x >=width,DVector<Point2>());
- ERR_FAIL_COND_V(to.y >=height,DVector<Point2>());
-
- if (from==to) {
- DVector<Point2> p;
- p.push_back(from);
- return p;
- }
-
- _lock();
-
-
- if (p_optimize) { //try a line first
-
- if (_is_linear_path(p_from,p_to)) {
- _unlock();
- DVector<Point2> p;
- p.push_back(from);
- p.push_back(to);
- return p;
- }
- }
-
-
- //clear all
- for(int i=0;i<width*height;i++) {
-
- bool s = cells[i].solid;
- cells[i].data=0;
- cells[i].solid=s;
- }
-
-#define CELL_INDEX(m_p) (m_p.y*width+m_p.x)
-#define CELL_COST(m_p) (cells[CELL_INDEX(m_p)].cost+( ABS(m_p.x-to.x)+ABS(m_p.y-to.y))*10)
-
-
- Set<Point2i> pending;
- pending.insert(from);
-
- //helper constants
- static const Point2i neighbour_rel[8]={
- Point2i(-1,-1), //0
- Point2i(-1, 0), //1
- Point2i(-1,+1), //2
- Point2i( 0,-1), //3
- Point2i( 0,+1), //4
- Point2i(+1,-1), //5
- Point2i(+1, 0), //6
- Point2i(+1,+1) }; //7
-
- static const int neighbour_cost[8]={
- 14,
- 10,
- 14,
- 10,
- 10,
- 14,
- 10,
- 14
- };
-
- static const int neighbour_parent[8]={
- 7,
- 6,
- 5,
- 4,
- 3,
- 2,
- 1,
- 0,
- };
-
- while(true) {
-
- if (pending.size() == 0) {
- _unlock();
- return DVector<Point2>(); // points don't connect
- }
- Point2i current;
- int lc=0x7FFFFFFF;
- { //find the one with the least cost
-
- Set<Point2i>::Element *Efound=NULL;
- for (Set<Point2i>::Element *E=pending.front();E;E=E->next()) {
-
- int cc =CELL_COST(E->get());
- if (cc<lc) {
- lc=cc;
- current=E->get();
- Efound=E;
-
- }
-
- }
- pending.erase(Efound);
- }
-
- Cell &c = cells[CELL_INDEX(current)];
-
- //search around other cells
-
-
- int accum_cost = (from==current) ? 0 : cells[CELL_INDEX((current + neighbour_rel[c.parent]))].cost;
-
- bool done=false;
-
- for(int i=0;i<8;i++) {
-
- Point2i neighbour=current+neighbour_rel[i];
- if (neighbour.x<0 || neighbour.y<0 || neighbour.x>=width || neighbour.y>=height)
- continue;
-
- Cell &n = cells[CELL_INDEX(neighbour)];
- if (n.solid)
- continue; //no good
-
- int cost = neighbour_cost[i]+accum_cost;
-
- if (n.visited && n.cost < cost)
- continue;
-
- n.cost=cost;
- n.parent=neighbour_parent[i];
- n.visited=true;
- pending.insert(neighbour);
- if (neighbour==to)
- done=true;
-
- }
-
- if (done)
- break;
- }
-
-
- // go througuh poins twice, first compute amount, then add them
-
- Point2i current=to;
- int pcount=0;
-
- while(true) {
-
- Cell &c = cells[CELL_INDEX(current)];
- c.visited=true;
- pcount++;
- if (current==from)
- break;
- current+=neighbour_rel[ c.parent ];
- }
-
- //now place them in an array
- DVector<Vector2> result;
- result.resize(pcount);
-
- DVector<Vector2>::Write res=result.write();
-
- current=to;
- int pidx=pcount-1;
-
- while(true) {
-
- Cell &c = cells[CELL_INDEX(current)];
- res[pidx]=current;
- pidx--;
- if (current==from)
- break;
- current+=neighbour_rel[ c.parent ];
- }
-
-
- //simplify..
-
-
- if (p_optimize) {
-
- int p=pcount-1;
- while(p>0) {
-
-
- int limit=p;
- while(limit>0) {
-
- limit--;
- if (!_can_go_straigth(res[p],res[limit]))
- break;
- }
-
-
- if (limit<p-1) {
- int diff = p-limit-1;
- pcount-=diff;
- for(int i=limit+1;i<pcount;i++) {
-
- res[i]=res[i+diff];
- }
- }
- p=limit;
- }
- }
-
- res=DVector<Vector2>::Write();
- result.resize(pcount);
- return result;
-}
-
-Size2 ImagePathFinder::get_size() const {
-
- return Size2(width,height);
-}
-bool ImagePathFinder::is_solid(const Point2& p_pos) {
-
-
- Point2i pos = p_pos;
-
- ERR_FAIL_COND_V(pos.x<0,true);
- ERR_FAIL_COND_V(pos.y<0,true);
- ERR_FAIL_COND_V(pos.x>=width,true);
- ERR_FAIL_COND_V(pos.y>=height,true);
-
- return cell_data[pos.y*width+pos.x].solid;
-}
-
-void ImagePathFinder::create_from_image_alpha(const Image& p_image) {
-
- ERR_FAIL_COND(p_image.get_format() != Image::FORMAT_RGBA);
- width = p_image.get_width();
- height = p_image.get_height();
- DVector<uint8_t> data = p_image.get_data();
- cell_data.resize(width * height);
- DVector<uint8_t>::Read read = data.read();
- DVector<Cell>::Write write = cell_data.write();
- for (int i=0; i<width * height; i++) {
- Cell cell;
- cell.data = 0;
- cell.solid = read[i*4+3] < 128;
- write[i] = cell;
- };
-};
-
-
-void ImagePathFinder::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("find_path","from","to","optimize"),&ImagePathFinder::find_path,DEFVAL(false));
- ObjectTypeDB::bind_method(_MD("get_size"),&ImagePathFinder::get_size);
- ObjectTypeDB::bind_method(_MD("is_solid","pos"),&ImagePathFinder::is_solid);
- ObjectTypeDB::bind_method(_MD("create_from_image_alpha"),&ImagePathFinder::create_from_image_alpha);
-}
-
-ImagePathFinder::ImagePathFinder()
-{
-
- cells=NULL;
- width=0;
- height=0;
-}
diff --git a/scene/resources/image_path_finder.h b/scene/resources/image_path_finder.h deleted file mode 100644 index e975ea5ed9..0000000000 --- a/scene/resources/image_path_finder.h +++ /dev/null @@ -1,84 +0,0 @@ -/*************************************************************************/ -/* image_path_finder.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef IMAGE_PATH_FINDER_H
-#define IMAGE_PATH_FINDER_H
-
-#include "resource.h"
-
-class ImagePathFinder : public Resource{
-
-
- OBJ_TYPE(ImagePathFinder,Resource);
- union Cell {
-
- struct {
- bool solid:1;
- bool visited:1;
- bool final:1;
- uint8_t parent:3;
- uint32_t cost:26;
- };
-
- uint32_t data;
- };
-
-
-
-
-
- DVector<Cell>::Write lock;
- DVector<Cell> cell_data;
-
- uint32_t width;
- uint32_t height;
- Cell* cells; //when unlocked
-
- void _unlock();
- void _lock();
-
-
- _FORCE_INLINE_ bool _can_go_straigth(const Point2& p_from, const Point2& p_to) const;
- _FORCE_INLINE_ bool _is_linear_path(const Point2& p_from, const Point2& p_to);
-
-protected:
-
- static void _bind_methods();
-public:
-
- DVector<Point2> find_path(const Point2& p_from, const Point2& p_to,bool p_optimize=false);
- Size2 get_size() const;
- bool is_solid(const Point2& p_pos);
- void create_from_image_alpha(const Image& p_image);
-
-
-
- ImagePathFinder();
-};
-
-#endif // IMAGE_PATH_FINDER_H
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 2314926b2b..355cc8884c 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -36,7 +36,8 @@ static const char*_flag_names[Material::FLAG_MAX]={ "invert_faces", "unshaded", "on_top", - "lightmap_on_uv2" + "lightmap_on_uv2", + "colarray_is_srgb" }; @@ -46,7 +47,8 @@ static const Material::Flag _flag_indices[Material::FLAG_MAX]={ Material::FLAG_INVERT_FACES, Material::FLAG_UNSHADED, Material::FLAG_ONTOP, - Material::FLAG_LIGHTMAP_ON_UV2 + Material::FLAG_LIGHTMAP_ON_UV2, + Material::FLAG_COLOR_ARRAY_SRGB, }; @@ -132,6 +134,8 @@ void Material::_bind_methods() { BIND_CONSTANT( FLAG_INVERT_FACES ); BIND_CONSTANT( FLAG_UNSHADED ); BIND_CONSTANT( FLAG_ONTOP ); + BIND_CONSTANT( FLAG_LIGHTMAP_ON_UV2 ); + BIND_CONSTANT( FLAG_COLOR_ARRAY_SRGB ); BIND_CONSTANT( FLAG_MAX ); BIND_CONSTANT( DEPTH_DRAW_ALWAYS ); @@ -156,6 +160,8 @@ Material::Material(const RID& p_material) { flags[FLAG_INVERT_FACES]=false; flags[FLAG_UNSHADED]=false; flags[FLAG_ONTOP]=false; + flags[FLAG_LIGHTMAP_ON_UV2]=true; + flags[FLAG_COLOR_ARRAY_SRGB]=false; depth_draw_mode=DEPTH_DRAW_OPAQUE_ONLY; @@ -316,14 +322,14 @@ Transform FixedMaterial::get_uv_transform() const { void FixedMaterial::set_fixed_flag(FixedFlag p_flag, bool p_value) { - ERR_FAIL_INDEX(p_flag,4); + ERR_FAIL_INDEX(p_flag,5); fixed_flags[p_flag]=p_value; VisualServer::get_singleton()->fixed_material_set_flag(material,(VS::FixedMaterialFlags)p_flag,p_value); } bool FixedMaterial::get_fixed_flag(FixedFlag p_flag) const { - ERR_FAIL_INDEX_V(p_flag,4,false); + ERR_FAIL_INDEX_V(p_flag,5,false); return fixed_flags[p_flag]; } @@ -371,6 +377,7 @@ void FixedMaterial::_bind_methods() { ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_color_array" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_COLOR_ARRAY); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_point_size" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_POINT_SIZE); ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/discard_alpha" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_DISCARD_ALPHA); + ADD_PROPERTYI( PropertyInfo( Variant::BOOL, "fixed_flags/use_xy_normalmap" ), _SCS("set_fixed_flag"), _SCS("get_fixed_flag"), FLAG_USE_XY_NORMALMAP); ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/diffuse" ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_DIFFUSE); ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/specular", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_SPECULAR ); ADD_PROPERTYI( PropertyInfo( Variant::COLOR, "params/emission", PROPERTY_HINT_COLOR_NO_ALPHA ), _SCS("set_parameter"), _SCS("get_parameter"), PARAM_EMISSION ); @@ -426,11 +433,14 @@ FixedMaterial::FixedMaterial() : Material(VS::get_singleton()->fixed_material_cr param[PARAM_SHADE_PARAM]=0.5; param[PARAM_DETAIL]=1.0; - + set_flag(FLAG_COLOR_ARRAY_SRGB,true); fixed_flags[FLAG_USE_ALPHA]=false; fixed_flags[FLAG_USE_COLOR_ARRAY]=false; fixed_flags[FLAG_USE_POINT_SIZE]=false; + fixed_flags[FLAG_USE_XY_NORMALMAP]=false; + fixed_flags[FLAG_DISCARD_ALPHA]=false; + for(int i=0;i<PARAM_MAX;i++) { @@ -448,6 +458,8 @@ FixedMaterial::~FixedMaterial() { } + + bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) { if (p_name==SceneStringNames::get_singleton()->shader_shader) { @@ -455,10 +467,20 @@ bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) { return true; } else { - String n = p_name; - if (n.begins_with("param/")) { - VisualServer::get_singleton()->material_set_param(material,String(n.ptr()+6),p_value); - return true; + if (shader.is_valid()) { + + + StringName pr = shader->remap_param(p_name); + if (!pr) { + String n = p_name; + if (n.find("param/")==0) { //backwards compatibility + pr = n.substr(6,n.length()); + } + } + if (pr) { + VisualServer::get_singleton()->material_set_param(material,pr,p_value); + return true; + } } } @@ -474,10 +496,13 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const { return true; } else { - String n = p_name; - if (n.begins_with("param/")) { - r_ret=VisualServer::get_singleton()->material_get_param(material,String(n.ptr()+6)); - return true; + if (shader.is_valid()) { + + StringName pr = shader->remap_param(p_name); + if (pr) { + r_ret=VisualServer::get_singleton()->material_get_param(material,pr); + return true; + } } } @@ -489,7 +514,7 @@ bool ShaderMaterial::_get(const StringName& p_name,Variant &r_ret) const { void ShaderMaterial::_get_property_list( List<PropertyInfo> *p_list) const { - p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"Shader" ) ); + p_list->push_back( PropertyInfo( Variant::OBJECT, "shader/shader", PROPERTY_HINT_RESOURCE_TYPE,"MaterialShader,MaterialShaderGraph" ) ); if (!shader.is_null()) { @@ -540,124 +565,34 @@ void ShaderMaterial::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_shader","shader:Shader"), &ShaderMaterial::set_shader ); ObjectTypeDB::bind_method(_MD("get_shader:Shader"), &ShaderMaterial::get_shader ); - ObjectTypeDB::bind_method(_MD("_shader_changed"), &ShaderMaterial::_shader_changed ); -} - - - - -ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){ - - -} - - -///////////////////////////////// - -void ParticleSystemMaterial::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_texture","texture"),&ParticleSystemMaterial::set_texture); - ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&ParticleSystemMaterial::get_texture); - - ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture" ), _SCS("set_texture"), _SCS("get_texture")); - -} - -void ParticleSystemMaterial::set_texture(const Ref<Texture>& p_texture) { - texture=p_texture; - RID rid; - if (texture.is_valid()) - rid=texture->get_rid(); - - VS::get_singleton()->fixed_material_set_texture(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,rid); -} - -Ref<Texture> ParticleSystemMaterial::get_texture() const { - - return texture; -} - - -ParticleSystemMaterial::ParticleSystemMaterial() :Material(VisualServer::get_singleton()->fixed_material_create()){ - set_flag(FLAG_DOUBLE_SIDED,true); - set_flag(FLAG_UNSHADED,true); - set_depth_draw_mode(DEPTH_DRAW_NEVER); - VisualServer::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_ALPHA,true); - VisualServer::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,true); -} - -ParticleSystemMaterial::~ParticleSystemMaterial() { - - -} - -////////////////////////////// - - - -void UnshadedMaterial::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("set_texture","texture"),&UnshadedMaterial::set_texture); - ObjectTypeDB::bind_method(_MD("get_texture:Texture"),&UnshadedMaterial::get_texture); - - ObjectTypeDB::bind_method(_MD("set_use_alpha","enable"),&UnshadedMaterial::set_use_alpha); - ObjectTypeDB::bind_method(_MD("is_using_alpha"),&UnshadedMaterial::is_using_alpha); - - ObjectTypeDB::bind_method(_MD("set_use_color_array","enable"),&UnshadedMaterial::set_use_color_array); - ObjectTypeDB::bind_method(_MD("is_using_color_array"),&UnshadedMaterial::is_using_color_array); - - ADD_PROPERTY( PropertyInfo( Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE,"Texture" ), _SCS("set_texture"), _SCS("get_texture")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "alpha" ), _SCS("set_use_alpha"), _SCS("is_using_alpha")); - ADD_PROPERTY( PropertyInfo( Variant::BOOL, "color_array" ), _SCS("set_use_color_array"), _SCS("is_using_color_array")); - -} - -void UnshadedMaterial::set_texture(const Ref<Texture>& p_texture) { - RID rid; - if (texture.is_valid()) - rid=texture->get_rid(); - - VS::get_singleton()->fixed_material_set_texture(material,VS::FIXED_MATERIAL_PARAM_DIFFUSE,rid); -} -Ref<Texture> UnshadedMaterial::get_texture() const { - - return texture; -} - -void UnshadedMaterial::set_use_alpha(bool p_use_alpha) { - - alpha=p_use_alpha; - VS::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_ALPHA,p_use_alpha); - //set_depth_draw_mode(); - //set_hint(HINT,p_use_alpha); + ObjectTypeDB::bind_method(_MD("set_shader_param","param","value:var"), &ShaderMaterial::set_shader_param); + ObjectTypeDB::bind_method(_MD("get_shader_param:var","param"), &ShaderMaterial::get_shader_param); + ObjectTypeDB::bind_method(_MD("_shader_changed"), &ShaderMaterial::_shader_changed ); } -bool UnshadedMaterial::is_using_alpha() const{ - - return alpha; -} -void UnshadedMaterial::set_use_color_array(bool p_use_color_array){ +void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const { - color_array=p_use_color_array; - VS::get_singleton()->fixed_material_set_flag(material,VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY,p_use_color_array); + String f = p_function.operator String(); + if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) { + if (shader.is_valid()) { + List<PropertyInfo> pl; + shader->get_param_list(&pl); + for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) { + r_options->push_back(E->get().name); + } + } + } + Material::get_argument_options(p_function,p_idx,r_options); } -bool UnshadedMaterial::is_using_color_array() const{ - - return color_array; -} +ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){ -UnshadedMaterial::UnshadedMaterial() :Material(VisualServer::get_singleton()->fixed_material_create()){ - set_flag(FLAG_UNSHADED,true); - set_use_alpha(true); } -UnshadedMaterial::~UnshadedMaterial() { - -} +///////////////////////////////// diff --git a/scene/resources/material.h b/scene/resources/material.h index 23ecb18fac..73d1a4e188 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -54,6 +54,7 @@ public: FLAG_UNSHADED = VS::MATERIAL_FLAG_UNSHADED, FLAG_ONTOP = VS::MATERIAL_FLAG_ONTOP, FLAG_LIGHTMAP_ON_UV2 = VS::MATERIAL_FLAG_LIGHTMAP_ON_UV2, + FLAG_COLOR_ARRAY_SRGB = VS::MATERIAL_FLAG_COLOR_ARRAY_SRGB, FLAG_MAX = VS::MATERIAL_FLAG_MAX }; @@ -141,7 +142,9 @@ public: FLAG_USE_ALPHA=VS::FIXED_MATERIAL_FLAG_USE_ALPHA, FLAG_USE_COLOR_ARRAY=VS::FIXED_MATERIAL_FLAG_USE_COLOR_ARRAY, FLAG_USE_POINT_SIZE=VS::FIXED_MATERIAL_FLAG_USE_POINT_SIZE, - FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA + FLAG_DISCARD_ALPHA=VS::FIXED_MATERIAL_FLAG_DISCARD_ALPHA, + FLAG_USE_XY_NORMALMAP=VS::FIXED_MATERIAL_FLAG_USE_XY_NORMALMAP, + FLAG_MAX=VS::FIXED_MATERIAL_FLAG_MAX }; enum LightShader { @@ -166,7 +169,7 @@ private: Ref<Texture> texture_param[PARAM_MAX]; TexCoordMode texture_texcoord[PARAM_MAX]; LightShader light_shader; - bool fixed_flags[3]; + bool fixed_flags[FLAG_MAX]; float point_size; @@ -240,6 +243,7 @@ public: void set_shader_param(const StringName& p_param,const Variant& p_value); Variant get_shader_param(const StringName& p_param) const; + void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const; ShaderMaterial(); }; @@ -249,68 +253,6 @@ public: -class ParticleSystemMaterial : public Material { - - OBJ_TYPE( ParticleSystemMaterial, Material ); - REVERSE_GET_PROPERTY_LIST - -private: - - - - Ref<Texture> texture; - -protected: - - - static void _bind_methods(); - -public: - - void set_texture(const Ref<Texture>& p_texture); - Ref<Texture> get_texture() const; - - - ParticleSystemMaterial(); - ~ParticleSystemMaterial(); - -}; - -/////////////////////////////////////////// - - -class UnshadedMaterial : public Material { - - OBJ_TYPE( UnshadedMaterial, Material ); - REVERSE_GET_PROPERTY_LIST - -private: - - - bool alpha; - bool color_array; - Ref<Texture> texture; - -protected: - - - static void _bind_methods(); - -public: - - void set_texture(const Ref<Texture>& p_texture); - Ref<Texture> get_texture() const; - - void set_use_alpha(bool p_use_alpha); - bool is_using_alpha() const; - - void set_use_color_array(bool p_use_color_array); - bool is_using_color_array() const; - - UnshadedMaterial(); - ~UnshadedMaterial(); - -}; #endif diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp index c6e492fcb3..f4bb3088c3 100644 --- a/scene/resources/mesh.cpp +++ b/scene/resources/mesh.cpp @@ -29,6 +29,7 @@ #include "mesh.h" #include "scene/resources/concave_polygon_shape.h" #include "scene/resources/convex_polygon_shape.h" +#include "surface_tool.h" static const char*_array_name[]={ "vertex_array", @@ -648,6 +649,30 @@ void Mesh::center_geometry() { } +void Mesh::regen_normalmaps() { + + + Vector< Ref<SurfaceTool> > surfs; + for(int i=0;i<get_surface_count();i++) { + + Ref<SurfaceTool> st = memnew( SurfaceTool ); + st->create_from(Ref<Mesh>(this),i); + surfs.push_back(st); + } + + while (get_surface_count()) { + surface_remove(0); + } + + for(int i=0;i<surfs.size();i++) { + + surfs[i]->generate_tangents(); + surfs[i]->commit(Ref<Mesh>(this)); + } +} + + + Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { if (triangle_mesh.is_valid()) @@ -718,6 +743,225 @@ Ref<TriangleMesh> Mesh::generate_triangle_mesh() const { } +Ref<Mesh> Mesh::create_outline(float p_margin) const { + + + Array arrays; + int index_accum=0; + for(int i=0;i<get_surface_count();i++) { + + if (surface_get_primitive_type(i)!=PRIMITIVE_TRIANGLES) + continue; + + Array a = surface_get_arrays(i); + int vcount=0; + + if (i==0) { + arrays=a; + DVector<Vector3> v=a[ARRAY_VERTEX]; + index_accum+=v.size(); + } else { + + for(int j=0;j<arrays.size();j++) { + + if (arrays[j].get_type()==Variant::NIL || a[j].get_type()==Variant::NIL) { + //mismatch, do not use + arrays[j]=Variant(); + continue; + } + + switch(j) { + + case ARRAY_VERTEX: + case ARRAY_NORMAL: { + + DVector<Vector3> dst = arrays[j]; + DVector<Vector3> src = a[j]; + if (j==ARRAY_VERTEX) + vcount=src.size(); + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + } break; + case ARRAY_TANGENT: + case ARRAY_BONES: + case ARRAY_WEIGHTS: { + + DVector<real_t> dst = arrays[j]; + DVector<real_t> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + + } break; + case ARRAY_COLOR: { + DVector<Color> dst = arrays[j]; + DVector<Color> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + + } break; + case ARRAY_TEX_UV: + case ARRAY_TEX_UV2: { + DVector<Vector2> dst = arrays[j]; + DVector<Vector2> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + dst.append_array(src); + arrays[j]=dst; + + } break; + case ARRAY_INDEX: { + DVector<int> dst = arrays[j]; + DVector<int> src = a[j]; + if (dst.size()==0 || src.size()==0) { + arrays[j]=Variant(); + continue; + } + { + int ss = src.size(); + DVector<int>::Write w = src.write(); + for(int k=0;k<ss;k++) { + w[k]+=index_accum; + } + + } + dst.append_array(src); + arrays[j]=dst; + index_accum+=vcount; + + } break; + + } + } + } + } + + { + int tc=0; + DVector<int>::Write ir; + DVector<int> indices =arrays[ARRAY_INDEX]; + bool has_indices=false; + DVector<Vector3> vertices =arrays[ARRAY_VERTEX]; + int vc = vertices.size(); + ERR_FAIL_COND_V(!vc,Ref<Mesh>()); + DVector<Vector3>::Write r=vertices.write(); + + + if (indices.size()) { + vc=indices.size(); + ir=indices.write(); + has_indices=true; + } + + Map<Vector3,Vector3> normal_accum; + + //fill normals with triangle normals + for(int i=0;i<vc;i+=3) { + + + Vector3 t[3]; + + if (has_indices) { + t[0]=r[ir[i+0]]; + t[1]=r[ir[i+1]]; + t[2]=r[ir[i+2]]; + } else { + t[0]=r[i+0]; + t[1]=r[i+1]; + t[2]=r[i+2]; + } + + Vector3 n = Plane(t[0],t[1],t[2]).normal; + + for(int j=0;j<3;j++) { + + Map<Vector3,Vector3>::Element *E=normal_accum.find(t[j]); + if (!E) { + normal_accum[t[j]]=n; + } else { + float d = n.dot(E->get()); + if (d<1.0) + E->get()+=n*(1.0-d); + //E->get()+=n; + } + } + } + + //normalize + + for (Map<Vector3,Vector3>::Element *E=normal_accum.front();E;E=E->next()) { + E->get().normalize(); + } + + + //displace normals + int vc2 = vertices.size(); + + for(int i=0;i<vc2;i++) { + + + Vector3 t=r[i]; + + Map<Vector3,Vector3>::Element *E=normal_accum.find(t); + ERR_CONTINUE(!E); + + t+=E->get()*p_margin; + r[i]=t; + } + + r = DVector<Vector3>::Write(); + arrays[ARRAY_VERTEX]=vertices; + + if (!has_indices) { + + DVector<int> new_indices; + new_indices.resize(vertices.size()); + DVector<int>::Write iw = new_indices.write(); + + for(int j=0;j<vc2;j+=3) { + + iw[j]=j; + iw[j+1]=j+2; + iw[j+2]=j+1; + } + + iw=DVector<int>::Write(); + arrays[ARRAY_INDEX]=new_indices; + + } else { + + for(int j=0;j<vc;j+=3) { + + SWAP(ir[j+1],ir[j+2]); + } + ir=DVector<int>::Write(); + arrays[ARRAY_INDEX]=indices; + + } + } + + + + + Ref<Mesh> newmesh = memnew( Mesh ); + newmesh->add_surface(PRIMITIVE_TRIANGLES,arrays); + return newmesh; +} + + void Mesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("add_morph_target","name"),&Mesh::add_morph_target); @@ -740,6 +984,8 @@ void Mesh::_bind_methods() { ObjectTypeDB::bind_method(_MD("surface_get_name","surf_idx"),&Mesh::surface_get_name); ObjectTypeDB::bind_method(_MD("center_geometry"),&Mesh::center_geometry); ObjectTypeDB::set_method_flags(get_type_static(),_SCS("center_geometry"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); + ObjectTypeDB::bind_method(_MD("regen_normalmaps"),&Mesh::regen_normalmaps); + ObjectTypeDB::set_method_flags(get_type_static(),_SCS("regen_normalmaps"),METHOD_FLAGS_DEFAULT|METHOD_FLAG_EDITOR); ObjectTypeDB::bind_method(_MD("set_custom_aabb","aabb"),&Mesh::set_custom_aabb); ObjectTypeDB::bind_method(_MD("get_custom_aabb"),&Mesh::get_custom_aabb); diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h index 5243163a4d..5aacc8be57 100644 --- a/scene/resources/mesh.h +++ b/scene/resources/mesh.h @@ -166,7 +166,10 @@ public: Ref<Shape> create_trimesh_shape() const; Ref<Shape> create_convex_shape() const; + Ref<Mesh> create_outline(float p_margin) const; + void center_geometry(); + void regen_normalmaps(); DVector<Face3> get_faces() const; Ref<TriangleMesh> generate_triangle_mesh() const; diff --git a/scene/resources/mikktspace.c b/scene/resources/mikktspace.c new file mode 100644 index 0000000000..62aa2da251 --- /dev/null +++ b/scene/resources/mikktspace.c @@ -0,0 +1,1890 @@ +/** \file mikktspace/mikktspace.c + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#include <assert.h> +#include <stdio.h> +#include <math.h> +#include <string.h> +#include <float.h> +#include <stdlib.h> + +#include "mikktspace.h" + +#define TFALSE 0 +#define TTRUE 1 + +#ifndef M_PI +#define M_PI 3.1415926535897932384626433832795 +#endif + +#define INTERNAL_RND_SORT_SEED 39871946 + +// internal structure +typedef struct { + float x, y, z; +} SVec3; + +static tbool veq( const SVec3 v1, const SVec3 v2 ) +{ + return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z); +} + +static SVec3 vadd( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x + v2.x; + vRes.y = v1.y + v2.y; + vRes.z = v1.z + v2.z; + + return vRes; +} + + +static SVec3 vsub( const SVec3 v1, const SVec3 v2 ) +{ + SVec3 vRes; + + vRes.x = v1.x - v2.x; + vRes.y = v1.y - v2.y; + vRes.z = v1.z - v2.z; + + return vRes; +} + +static SVec3 vscale(const float fS, const SVec3 v) +{ + SVec3 vRes; + + vRes.x = fS * v.x; + vRes.y = fS * v.y; + vRes.z = fS * v.z; + + return vRes; +} + +static float LengthSquared( const SVec3 v ) +{ + return v.x*v.x + v.y*v.y + v.z*v.z; +} + +static float Length( const SVec3 v ) +{ + return sqrtf(LengthSquared(v)); +} + +static SVec3 Normalize( const SVec3 v ) +{ + return vscale(1 / Length(v), v); +} + +static float vdot( const SVec3 v1, const SVec3 v2) +{ + return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z; +} + + +static tbool NotZero(const float fX) +{ + // could possibly use FLT_EPSILON instead + return fabsf(fX) > FLT_MIN; +} + +static tbool VNotZero(const SVec3 v) +{ + // might change this to an epsilon based test + return NotZero(v.x) || NotZero(v.y) || NotZero(v.z); +} + + + +typedef struct { + int iNrFaces; + int * pTriMembers; +} SSubGroup; + +typedef struct { + int iNrFaces; + int * pFaceIndices; + int iVertexRepresentitive; + tbool bOrientPreservering; +} SGroup; + +// +#define MARK_DEGENERATE 1 +#define QUAD_ONE_DEGEN_TRI 2 +#define GROUP_WITH_ANY 4 +#define ORIENT_PRESERVING 8 + + + +typedef struct { + int FaceNeighbors[3]; + SGroup * AssignedGroup[3]; + + // normalized first order face derivatives + SVec3 vOs, vOt; + float fMagS, fMagT; // original magnitudes + + // determines if the current and the next triangle are a quad. + int iOrgFaceNumber; + int iFlag, iTSpacesOffs; + unsigned char vert_num[4]; +} STriInfo; + +typedef struct { + SVec3 vOs; + float fMagS; + SVec3 vOt; + float fMagT; + int iCounter; // this is to average back into quads. + tbool bOrient; +} STSpace; + +static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn); +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext); + +static int MakeIndex(const int iFace, const int iVert) +{ + assert(iVert>=0 && iVert<4 && iFace>=0); + return (iFace<<2) | (iVert&0x3); +} + +static void IndexToData(int * piFace, int * piVert, const int iIndexIn) +{ + piVert[0] = iIndexIn&0x3; + piFace[0] = iIndexIn>>2; +} + +static STSpace AvgTSpace(const STSpace * pTS0, const STSpace * pTS1) +{ + STSpace ts_res; + + // this if is important. Due to floating point precision + // averaging when ts0==ts1 will cause a slight difference + // which results in tangent space splits later on + if (pTS0->fMagS==pTS1->fMagS && pTS0->fMagT==pTS1->fMagT && + veq(pTS0->vOs,pTS1->vOs) && veq(pTS0->vOt, pTS1->vOt)) + { + ts_res.fMagS = pTS0->fMagS; + ts_res.fMagT = pTS0->fMagT; + ts_res.vOs = pTS0->vOs; + ts_res.vOt = pTS0->vOt; + } + else + { + ts_res.fMagS = 0.5f*(pTS0->fMagS+pTS1->fMagS); + ts_res.fMagT = 0.5f*(pTS0->fMagT+pTS1->fMagT); + ts_res.vOs = vadd(pTS0->vOs,pTS1->vOs); + ts_res.vOt = vadd(pTS0->vOt,pTS1->vOt); + if ( VNotZero(ts_res.vOs) ) ts_res.vOs = Normalize(ts_res.vOs); + if ( VNotZero(ts_res.vOt) ) ts_res.vOt = Normalize(ts_res.vOt); + } + + return ts_res; +} + + + +static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index); +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index); + + +// degen triangles +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris); +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris); + + +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext) +{ + return genTangSpace(pContext, 180.0f); +} + +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold) +{ + // count nr_triangles + int * piTriListIn = NULL, * piGroupTrianglesBuffer = NULL; + STriInfo * pTriInfos = NULL; + SGroup * pGroups = NULL; + STSpace * psTspace = NULL; + int iNrTrianglesIn = 0, f=0, t=0, i=0; + int iNrTSPaces = 0, iTotTris = 0, iDegenTriangles = 0, iNrMaxGroups = 0; + int iNrActiveGroups = 0, index = 0; + const int iNrFaces = pContext->m_pInterface->m_getNumFaces(pContext); + tbool bRes = TFALSE; + const float fThresCos = (float) cos((fAngularThreshold*(float)M_PI)/180.0f); + + // verify all call-backs have been set + if ( pContext->m_pInterface->m_getNumFaces==NULL || + pContext->m_pInterface->m_getNumVerticesOfFace==NULL || + pContext->m_pInterface->m_getPosition==NULL || + pContext->m_pInterface->m_getNormal==NULL || + pContext->m_pInterface->m_getTexCoord==NULL ) + return TFALSE; + + // count triangles on supported faces + for (f=0; f<iNrFaces; f++) + { + const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts==3) ++iNrTrianglesIn; + else if (verts==4) iNrTrianglesIn += 2; + } + if (iNrTrianglesIn<=0) return TFALSE; + + // allocate memory for an index list + piTriListIn = (int *) malloc(sizeof(int)*3*iNrTrianglesIn); + pTriInfos = (STriInfo *) malloc(sizeof(STriInfo)*iNrTrianglesIn); + if (piTriListIn==NULL || pTriInfos==NULL) + { + if (piTriListIn!=NULL) free(piTriListIn); + if (pTriInfos!=NULL) free(pTriInfos); + return TFALSE; + } + + // make an initial triangle --> face index list + iNrTSPaces = GenerateInitialVerticesIndexList(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); + + // make a welded index list of identical positions and attributes (pos, norm, texc) + //printf("gen welded index list begin\n"); + GenerateSharedVerticesIndexList(piTriListIn, pContext, iNrTrianglesIn); + //printf("gen welded index list end\n"); + + // Mark all degenerate triangles + iTotTris = iNrTrianglesIn; + iDegenTriangles = 0; + for (t=0; t<iTotTris; t++) + { + const int i0 = piTriListIn[t*3+0]; + const int i1 = piTriListIn[t*3+1]; + const int i2 = piTriListIn[t*3+2]; + const SVec3 p0 = GetPosition(pContext, i0); + const SVec3 p1 = GetPosition(pContext, i1); + const SVec3 p2 = GetPosition(pContext, i2); + if (veq(p0,p1) || veq(p0,p2) || veq(p1,p2)) // degenerate + { + pTriInfos[t].iFlag |= MARK_DEGENERATE; + ++iDegenTriangles; + } + } + iNrTrianglesIn = iTotTris - iDegenTriangles; + + // mark all triangle pairs that belong to a quad with only one + // good triangle. These need special treatment in DegenEpilogue(). + // Additionally, move all good triangles to the start of + // pTriInfos[] and piTriListIn[] without changing order and + // put the degenerate triangles last. + DegenPrologue(pTriInfos, piTriListIn, iNrTrianglesIn, iTotTris); + + + // evaluate triangle level attributes and neighbor list + //printf("gen neighbors list begin\n"); + InitTriInfo(pTriInfos, piTriListIn, pContext, iNrTrianglesIn); + //printf("gen neighbors list end\n"); + + + // based on the 4 rules, identify groups based on connectivity + iNrMaxGroups = iNrTrianglesIn*3; + pGroups = (SGroup *) malloc(sizeof(SGroup)*iNrMaxGroups); + piGroupTrianglesBuffer = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + if (pGroups==NULL || piGroupTrianglesBuffer==NULL) + { + if (pGroups!=NULL) free(pGroups); + if (piGroupTrianglesBuffer!=NULL) free(piGroupTrianglesBuffer); + free(piTriListIn); + free(pTriInfos); + return TFALSE; + } + //printf("gen 4rule groups begin\n"); + iNrActiveGroups = + Build4RuleGroups(pTriInfos, pGroups, piGroupTrianglesBuffer, piTriListIn, iNrTrianglesIn); + //printf("gen 4rule groups end\n"); + + // + + psTspace = (STSpace *) malloc(sizeof(STSpace)*iNrTSPaces); + if (psTspace==NULL) + { + free(piTriListIn); + free(pTriInfos); + free(pGroups); + free(piGroupTrianglesBuffer); + return TFALSE; + } + memset(psTspace, 0, sizeof(STSpace)*iNrTSPaces); + for (t=0; t<iNrTSPaces; t++) + { + psTspace[t].vOs.x=1.0f; psTspace[t].vOs.y=0.0f; psTspace[t].vOs.z=0.0f; psTspace[t].fMagS = 1.0f; + psTspace[t].vOt.x=0.0f; psTspace[t].vOt.y=1.0f; psTspace[t].vOt.z=0.0f; psTspace[t].fMagT = 1.0f; + } + + // make tspaces, each group is split up into subgroups if necessary + // based on fAngularThreshold. Finally a tangent space is made for + // every resulting subgroup + //printf("gen tspaces begin\n"); + bRes = GenerateTSpaces(psTspace, pTriInfos, pGroups, iNrActiveGroups, piTriListIn, fThresCos, pContext); + //printf("gen tspaces end\n"); + + // clean up + free(pGroups); + free(piGroupTrianglesBuffer); + + if (!bRes) // if an allocation in GenerateTSpaces() failed + { + // clean up and return false + free(pTriInfos); free(piTriListIn); free(psTspace); + return TFALSE; + } + + + // degenerate quads with one good triangle will be fixed by copying a space from + // the good triangle to the coinciding vertex. + // all other degenerate triangles will just copy a space from any good triangle + // with the same welded index in piTriListIn[]. + DegenEpilogue(psTspace, pTriInfos, piTriListIn, pContext, iNrTrianglesIn, iTotTris); + + free(pTriInfos); free(piTriListIn); + + index = 0; + for (f=0; f<iNrFaces; f++) + { + const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + + // I've decided to let degenerate triangles and group-with-anythings + // vary between left/right hand coordinate systems at the vertices. + // All healthy triangles on the other hand are built to always be either or. + + /*// force the coordinate system orientation to be uniform for every face. + // (this is already the case for good triangles but not for + // degenerate ones and those with bGroupWithAnything==true) + bool bOrient = psTspace[index].bOrient; + if (psTspace[index].iCounter == 0) // tspace was not derived from a group + { + // look for a space created in GenerateTSpaces() by iCounter>0 + bool bNotFound = true; + int i=1; + while (i<verts && bNotFound) + { + if (psTspace[index+i].iCounter > 0) bNotFound=false; + else ++i; + } + if (!bNotFound) bOrient = psTspace[index+i].bOrient; + }*/ + + // set data + for (i=0; i<verts; i++) + { + const STSpace * pTSpace = &psTspace[index]; + float tang[] = {pTSpace->vOs.x, pTSpace->vOs.y, pTSpace->vOs.z}; + float bitang[] = {pTSpace->vOt.x, pTSpace->vOt.y, pTSpace->vOt.z}; + if (pContext->m_pInterface->m_setTSpace!=NULL) + pContext->m_pInterface->m_setTSpace(pContext, tang, bitang, pTSpace->fMagS, pTSpace->fMagT, pTSpace->bOrient, f, i); + if (pContext->m_pInterface->m_setTSpaceBasic!=NULL) + pContext->m_pInterface->m_setTSpaceBasic(pContext, tang, pTSpace->bOrient==TTRUE ? 1.0f : (-1.0f), f, i); + + ++index; + } + } + + free(psTspace); + + + return TTRUE; +} + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef struct { + float vert[3]; + int index; +} STmpVert; + +static const int g_iCells = 2048; + +#ifdef _MSC_VER + #define NOINLINE __declspec(noinline) +#else + #define NOINLINE __attribute__ ((noinline)) +#endif + +// it is IMPORTANT that this function is called to evaluate the hash since +// inlining could potentially reorder instructions and generate different +// results for the same effective input value fVal. +static NOINLINE int FindGridCell(const float fMin, const float fMax, const float fVal) +{ + const float fIndex = g_iCells * ((fVal-fMin)/(fMax-fMin)); + const int iIndex = (int)fIndex; + return iIndex < g_iCells ? (iIndex >= 0 ? iIndex : 0) : (g_iCells - 1); +} + +static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in); +static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries); +static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn); + +static void GenerateSharedVerticesIndexList(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + + // Generate bounding box + int * piHashTable=NULL, * piHashCount=NULL, * piHashOffsets=NULL, * piHashCount2=NULL; + STmpVert * pTmpVert = NULL; + int i=0, iChannel=0, k=0, e=0; + int iMaxCount=0; + SVec3 vMin = GetPosition(pContext, 0), vMax = vMin, vDim; + float fMin, fMax; + for (i=1; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + + const SVec3 vP = GetPosition(pContext, index); + if (vMin.x > vP.x) vMin.x = vP.x; + else if (vMax.x < vP.x) vMax.x = vP.x; + if (vMin.y > vP.y) vMin.y = vP.y; + else if (vMax.y < vP.y) vMax.y = vP.y; + if (vMin.z > vP.z) vMin.z = vP.z; + else if (vMax.z < vP.z) vMax.z = vP.z; + } + + vDim = vsub(vMax,vMin); + iChannel = 0; + fMin = vMin.x; fMax=vMax.x; + if (vDim.y>vDim.x && vDim.y>vDim.z) + { + iChannel=1; + fMin = vMin.y, fMax=vMax.y; + } + else if (vDim.z>vDim.x) + { + iChannel=2; + fMin = vMin.z, fMax=vMax.z; + } + + // make allocations + piHashTable = (int *) malloc(sizeof(int)*iNrTrianglesIn*3); + piHashCount = (int *) malloc(sizeof(int)*g_iCells); + piHashOffsets = (int *) malloc(sizeof(int)*g_iCells); + piHashCount2 = (int *) malloc(sizeof(int)*g_iCells); + + if (piHashTable==NULL || piHashCount==NULL || piHashOffsets==NULL || piHashCount2==NULL) + { + if (piHashTable!=NULL) free(piHashTable); + if (piHashCount!=NULL) free(piHashCount); + if (piHashOffsets!=NULL) free(piHashOffsets); + if (piHashCount2!=NULL) free(piHashCount2); + GenerateSharedVerticesIndexListSlow(piTriList_in_and_out, pContext, iNrTrianglesIn); + return; + } + memset(piHashCount, 0, sizeof(int)*g_iCells); + memset(piHashCount2, 0, sizeof(int)*g_iCells); + + // count amount of elements in each cell unit + for (i=0; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); + const int iCell = FindGridCell(fMin, fMax, fVal); + ++piHashCount[iCell]; + } + + // evaluate start index of each cell. + piHashOffsets[0]=0; + for (k=1; k<g_iCells; k++) + piHashOffsets[k]=piHashOffsets[k-1]+piHashCount[k-1]; + + // insert vertices + for (i=0; i<(iNrTrianglesIn*3); i++) + { + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const float fVal = iChannel==0 ? vP.x : (iChannel==1 ? vP.y : vP.z); + const int iCell = FindGridCell(fMin, fMax, fVal); + int * pTable = NULL; + + assert(piHashCount2[iCell]<piHashCount[iCell]); + pTable = &piHashTable[piHashOffsets[iCell]]; + pTable[piHashCount2[iCell]] = i; // vertex i has been inserted. + ++piHashCount2[iCell]; + } + for (k=0; k<g_iCells; k++) + assert(piHashCount2[k] == piHashCount[k]); // verify the count + free(piHashCount2); + + // find maximum amount of entries in any hash entry + iMaxCount = piHashCount[0]; + for (k=1; k<g_iCells; k++) + if (iMaxCount<piHashCount[k]) + iMaxCount=piHashCount[k]; + pTmpVert = (STmpVert *) malloc(sizeof(STmpVert)*iMaxCount); + + + // complete the merge + for (k=0; k<g_iCells; k++) + { + // extract table of cell k and amount of entries in it + int * pTable = &piHashTable[piHashOffsets[k]]; + const int iEntries = piHashCount[k]; + if (iEntries < 2) continue; + + if (pTmpVert!=NULL) + { + for (e=0; e<iEntries; e++) + { + int i = pTable[e]; + const SVec3 vP = GetPosition(pContext, piTriList_in_and_out[i]); + pTmpVert[e].vert[0] = vP.x; pTmpVert[e].vert[1] = vP.y; + pTmpVert[e].vert[2] = vP.z; pTmpVert[e].index = i; + } + MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, 0, iEntries-1); + } + else + MergeVertsSlow(piTriList_in_and_out, pContext, pTable, iEntries); + } + + if (pTmpVert!=NULL) { free(pTmpVert); } + free(piHashTable); + free(piHashCount); + free(piHashOffsets); +} + +static void MergeVertsFast(int piTriList_in_and_out[], STmpVert pTmpVert[], const SMikkTSpaceContext * pContext, const int iL_in, const int iR_in) +{ + // make bbox + int c=0, l=0, channel=0; + float fvMin[3], fvMax[3]; + float dx=0, dy=0, dz=0, fSep=0; + for (c=0; c<3; c++) + { fvMin[c]=pTmpVert[iL_in].vert[c]; fvMax[c]=fvMin[c]; } + for (l=(iL_in+1); l<=iR_in; l++) + for (c=0; c<3; c++) + if (fvMin[c]>pTmpVert[l].vert[c]) fvMin[c]=pTmpVert[l].vert[c]; + else if (fvMax[c]<pTmpVert[l].vert[c]) fvMax[c]=pTmpVert[l].vert[c]; + + dx = fvMax[0]-fvMin[0]; + dy = fvMax[1]-fvMin[1]; + dz = fvMax[2]-fvMin[2]; + + channel = 0; + if (dy>dx && dy>dz) channel=1; + else if (dz>dx) channel=2; + + fSep = 0.5f*(fvMax[channel]+fvMin[channel]); + + // terminate recursion when the separation/average value + // is no longer strictly between fMin and fMax values. + if (fSep>=fvMax[channel] || fSep<=fvMin[channel]) + { + // complete the weld + for (l=iL_in; l<=iR_in; l++) + { + int i = pTmpVert[l].index; + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const SVec3 vN = GetNormal(pContext, index); + const SVec3 vT = GetTexCoord(pContext, index); + + tbool bNotFound = TTRUE; + int l2=iL_in, i2rec=-1; + while (l2<l && bNotFound) + { + const int i2 = pTmpVert[l2].index; + const int index2 = piTriList_in_and_out[i2]; + const SVec3 vP2 = GetPosition(pContext, index2); + const SVec3 vN2 = GetNormal(pContext, index2); + const SVec3 vT2 = GetTexCoord(pContext, index2); + i2rec=i2; + + //if (vP==vP2 && vN==vN2 && vT==vT2) + if (vP.x==vP2.x && vP.y==vP2.y && vP.z==vP2.z && + vN.x==vN2.x && vN.y==vN2.y && vN.z==vN2.z && + vT.x==vT2.x && vT.y==vT2.y && vT.z==vT2.z) + bNotFound = TFALSE; + else + ++l2; + } + + // merge if previously found + if (!bNotFound) + piTriList_in_and_out[i] = piTriList_in_and_out[i2rec]; + } + } + else + { + int iL=iL_in, iR=iR_in; + assert((iR_in-iL_in)>0); // at least 2 entries + + // separate (by fSep) all points between iL_in and iR_in in pTmpVert[] + while (iL < iR) + { + tbool bReadyLeftSwap = TFALSE, bReadyRightSwap = TFALSE; + while ((!bReadyLeftSwap) && iL<iR) + { + assert(iL>=iL_in && iL<=iR_in); + bReadyLeftSwap = !(pTmpVert[iL].vert[channel]<fSep); + if (!bReadyLeftSwap) ++iL; + } + while ((!bReadyRightSwap) && iL<iR) + { + assert(iR>=iL_in && iR<=iR_in); + bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep; + if (!bReadyRightSwap) --iR; + } + assert( (iL<iR) || !(bReadyLeftSwap && bReadyRightSwap) ); + + if (bReadyLeftSwap && bReadyRightSwap) + { + const STmpVert sTmp = pTmpVert[iL]; + assert(iL<iR); + pTmpVert[iL] = pTmpVert[iR]; + pTmpVert[iR] = sTmp; + ++iL; --iR; + } + } + + assert(iL==(iR+1) || (iL==iR)); + if (iL==iR) + { + const tbool bReadyRightSwap = pTmpVert[iR].vert[channel]<fSep; + if (bReadyRightSwap) ++iL; + else --iR; + } + + // only need to weld when there is more than 1 instance of the (x,y,z) + if (iL_in < iR) + MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL_in, iR); // weld all left of fSep + if (iL < iR_in) + MergeVertsFast(piTriList_in_and_out, pTmpVert, pContext, iL, iR_in); // weld all right of (or equal to) fSep + } +} + +static void MergeVertsSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int pTable[], const int iEntries) +{ + // this can be optimized further using a tree structure or more hashing. + int e=0; + for (e=0; e<iEntries; e++) + { + int i = pTable[e]; + const int index = piTriList_in_and_out[i]; + const SVec3 vP = GetPosition(pContext, index); + const SVec3 vN = GetNormal(pContext, index); + const SVec3 vT = GetTexCoord(pContext, index); + + tbool bNotFound = TTRUE; + int e2=0, i2rec=-1; + while (e2<e && bNotFound) + { + const int i2 = pTable[e2]; + const int index2 = piTriList_in_and_out[i2]; + const SVec3 vP2 = GetPosition(pContext, index2); + const SVec3 vN2 = GetNormal(pContext, index2); + const SVec3 vT2 = GetTexCoord(pContext, index2); + i2rec = i2; + + if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2)) + bNotFound = TFALSE; + else + ++e2; + } + + // merge if previously found + if (!bNotFound) + piTriList_in_and_out[i] = piTriList_in_and_out[i2rec]; + } +} + +static void GenerateSharedVerticesIndexListSlow(int piTriList_in_and_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + int iNumUniqueVerts = 0, t=0, i=0; + for (t=0; t<iNrTrianglesIn; t++) + { + for (i=0; i<3; i++) + { + const int offs = t*3 + i; + const int index = piTriList_in_and_out[offs]; + + const SVec3 vP = GetPosition(pContext, index); + const SVec3 vN = GetNormal(pContext, index); + const SVec3 vT = GetTexCoord(pContext, index); + + tbool bFound = TFALSE; + int t2=0, index2rec=-1; + while (!bFound && t2<=t) + { + int j=0; + while (!bFound && j<3) + { + const int index2 = piTriList_in_and_out[t2*3 + j]; + const SVec3 vP2 = GetPosition(pContext, index2); + const SVec3 vN2 = GetNormal(pContext, index2); + const SVec3 vT2 = GetTexCoord(pContext, index2); + + if (veq(vP,vP2) && veq(vN,vN2) && veq(vT,vT2)) + bFound = TTRUE; + else + ++j; + } + if (!bFound) ++t2; + } + + assert(bFound); + // if we found our own + if (index2rec == index) { ++iNumUniqueVerts; } + + piTriList_in_and_out[offs] = index2rec; + } + } +} + +static int GenerateInitialVerticesIndexList(STriInfo pTriInfos[], int piTriList_out[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + int iTSpacesOffs = 0, f=0, t=0; + int iDstTriIndex = 0; + for (f=0; f<pContext->m_pInterface->m_getNumFaces(pContext); f++) + { + const int verts = pContext->m_pInterface->m_getNumVerticesOfFace(pContext, f); + if (verts!=3 && verts!=4) continue; + + pTriInfos[iDstTriIndex].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex].iTSpacesOffs = iTSpacesOffs; + + if (verts==3) + { + unsigned char * pVerts = pTriInfos[iDstTriIndex].vert_num; + pVerts[0]=0; pVerts[1]=1; pVerts[2]=2; + piTriList_out[iDstTriIndex*3+0] = MakeIndex(f, 0); + piTriList_out[iDstTriIndex*3+1] = MakeIndex(f, 1); + piTriList_out[iDstTriIndex*3+2] = MakeIndex(f, 2); + ++iDstTriIndex; // next + } + else + { + { + pTriInfos[iDstTriIndex+1].iOrgFaceNumber = f; + pTriInfos[iDstTriIndex+1].iTSpacesOffs = iTSpacesOffs; + } + + { + // need an order independent way to evaluate + // tspace on quads. This is done by splitting + // along the shortest diagonal. + const int i0 = MakeIndex(f, 0); + const int i1 = MakeIndex(f, 1); + const int i2 = MakeIndex(f, 2); + const int i3 = MakeIndex(f, 3); + const SVec3 T0 = GetTexCoord(pContext, i0); + const SVec3 T1 = GetTexCoord(pContext, i1); + const SVec3 T2 = GetTexCoord(pContext, i2); + const SVec3 T3 = GetTexCoord(pContext, i3); + const float distSQ_02 = LengthSquared(vsub(T2,T0)); + const float distSQ_13 = LengthSquared(vsub(T3,T1)); + tbool bQuadDiagIs_02; + if (distSQ_02<distSQ_13) + bQuadDiagIs_02 = TTRUE; + else if (distSQ_13<distSQ_02) + bQuadDiagIs_02 = TFALSE; + else + { + const SVec3 P0 = GetPosition(pContext, i0); + const SVec3 P1 = GetPosition(pContext, i1); + const SVec3 P2 = GetPosition(pContext, i2); + const SVec3 P3 = GetPosition(pContext, i3); + const float distSQ_02 = LengthSquared(vsub(P2,P0)); + const float distSQ_13 = LengthSquared(vsub(P3,P1)); + + bQuadDiagIs_02 = distSQ_13<distSQ_02 ? TFALSE : TTRUE; + } + + if (bQuadDiagIs_02) + { + { + unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num; + pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=2; + } + piTriList_out[iDstTriIndex*3+0] = i0; + piTriList_out[iDstTriIndex*3+1] = i1; + piTriList_out[iDstTriIndex*3+2] = i2; + ++iDstTriIndex; // next + { + unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num; + pVerts_B[0]=0; pVerts_B[1]=2; pVerts_B[2]=3; + } + piTriList_out[iDstTriIndex*3+0] = i0; + piTriList_out[iDstTriIndex*3+1] = i2; + piTriList_out[iDstTriIndex*3+2] = i3; + ++iDstTriIndex; // next + } + else + { + { + unsigned char * pVerts_A = pTriInfos[iDstTriIndex].vert_num; + pVerts_A[0]=0; pVerts_A[1]=1; pVerts_A[2]=3; + } + piTriList_out[iDstTriIndex*3+0] = i0; + piTriList_out[iDstTriIndex*3+1] = i1; + piTriList_out[iDstTriIndex*3+2] = i3; + ++iDstTriIndex; // next + { + unsigned char * pVerts_B = pTriInfos[iDstTriIndex].vert_num; + pVerts_B[0]=1; pVerts_B[1]=2; pVerts_B[2]=3; + } + piTriList_out[iDstTriIndex*3+0] = i1; + piTriList_out[iDstTriIndex*3+1] = i2; + piTriList_out[iDstTriIndex*3+2] = i3; + ++iDstTriIndex; // next + } + } + } + + iTSpacesOffs += verts; + assert(iDstTriIndex<=iNrTrianglesIn); + } + + for (t=0; t<iNrTrianglesIn; t++) + pTriInfos[t].iFlag = 0; + + // return total amount of tspaces + return iTSpacesOffs; +} + +static SVec3 GetPosition(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float pos[3]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getPosition(pContext, pos, iF, iI); + res.x=pos[0]; res.y=pos[1]; res.z=pos[2]; + return res; +} + +static SVec3 GetNormal(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float norm[3]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getNormal(pContext, norm, iF, iI); + res.x=norm[0]; res.y=norm[1]; res.z=norm[2]; + return res; +} + +static SVec3 GetTexCoord(const SMikkTSpaceContext * pContext, const int index) +{ + int iF, iI; + SVec3 res; float texc[2]; + IndexToData(&iF, &iI, index); + pContext->m_pInterface->m_getTexCoord(pContext, texc, iF, iI); + res.x=texc[0]; res.y=texc[1]; res.z=1.0f; + return res; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +typedef union { + struct + { + int i0, i1, f; + }; + int array[3]; +} SEdge; + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn); +static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn); + +// returns the texture area times 2 +static float CalcTexArea(const SMikkTSpaceContext * pContext, const int indices[]) +{ + const SVec3 t1 = GetTexCoord(pContext, indices[0]); + const SVec3 t2 = GetTexCoord(pContext, indices[1]); + const SVec3 t3 = GetTexCoord(pContext, indices[2]); + + const float t21x = t2.x-t1.x; + const float t21y = t2.y-t1.y; + const float t31x = t3.x-t1.x; + const float t31y = t3.y-t1.y; + + const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; + + return fSignedAreaSTx2<0 ? (-fSignedAreaSTx2) : fSignedAreaSTx2; +} + +static void InitTriInfo(STriInfo pTriInfos[], const int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn) +{ + int f=0, i=0, t=0; + // pTriInfos[f].iFlag is cleared in GenerateInitialVerticesIndexList() which is called before this function. + + // generate neighbor info list + for (f=0; f<iNrTrianglesIn; f++) + for (i=0; i<3; i++) + { + pTriInfos[f].FaceNeighbors[i] = -1; + pTriInfos[f].AssignedGroup[i] = NULL; + + pTriInfos[f].vOs.x=0.0f; pTriInfos[f].vOs.y=0.0f; pTriInfos[f].vOs.z=0.0f; + pTriInfos[f].vOt.x=0.0f; pTriInfos[f].vOt.y=0.0f; pTriInfos[f].vOt.z=0.0f; + pTriInfos[f].fMagS = 0; + pTriInfos[f].fMagT = 0; + + // assumed bad + pTriInfos[f].iFlag |= GROUP_WITH_ANY; + } + + // evaluate first order derivatives + for (f=0; f<iNrTrianglesIn; f++) + { + // initial values + const SVec3 v1 = GetPosition(pContext, piTriListIn[f*3+0]); + const SVec3 v2 = GetPosition(pContext, piTriListIn[f*3+1]); + const SVec3 v3 = GetPosition(pContext, piTriListIn[f*3+2]); + const SVec3 t1 = GetTexCoord(pContext, piTriListIn[f*3+0]); + const SVec3 t2 = GetTexCoord(pContext, piTriListIn[f*3+1]); + const SVec3 t3 = GetTexCoord(pContext, piTriListIn[f*3+2]); + + const float t21x = t2.x-t1.x; + const float t21y = t2.y-t1.y; + const float t31x = t3.x-t1.x; + const float t31y = t3.y-t1.y; + const SVec3 d1 = vsub(v2,v1); + const SVec3 d2 = vsub(v3,v1); + + const float fSignedAreaSTx2 = t21x*t31y - t21y*t31x; + //assert(fSignedAreaSTx2!=0); + SVec3 vOs = vsub(vscale(t31y,d1), vscale(t21y,d2)); // eq 18 + SVec3 vOt = vadd(vscale(-t31x,d1), vscale(t21x,d2)); // eq 19 + + pTriInfos[f].iFlag |= (fSignedAreaSTx2>0 ? ORIENT_PRESERVING : 0); + + if ( NotZero(fSignedAreaSTx2) ) + { + const float fAbsArea = fabsf(fSignedAreaSTx2); + const float fLenOs = Length(vOs); + const float fLenOt = Length(vOt); + const float fS = (pTriInfos[f].iFlag&ORIENT_PRESERVING)==0 ? (-1.0f) : 1.0f; + if ( NotZero(fLenOs) ) pTriInfos[f].vOs = vscale(fS/fLenOs, vOs); + if ( NotZero(fLenOt) ) pTriInfos[f].vOt = vscale(fS/fLenOt, vOt); + + // evaluate magnitudes prior to normalization of vOs and vOt + pTriInfos[f].fMagS = fLenOs / fAbsArea; + pTriInfos[f].fMagT = fLenOt / fAbsArea; + + // if this is a good triangle + if ( NotZero(pTriInfos[f].fMagS) && NotZero(pTriInfos[f].fMagT)) + pTriInfos[f].iFlag &= (~GROUP_WITH_ANY); + } + } + + // force otherwise healthy quads to a fixed orientation + while (t<(iNrTrianglesIn-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + + // bad triangles should already have been removed by + // DegenPrologue(), but just in case check bIsDeg_a and bIsDeg_a are false + if ((bIsDeg_a||bIsDeg_b)==TFALSE) + { + const tbool bOrientA = (pTriInfos[t].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bOrientB = (pTriInfos[t+1].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + // if this happens the quad has extremely bad mapping!! + if (bOrientA!=bOrientB) + { + //printf("found quad with bad mapping\n"); + tbool bChooseOrientFirstTri = TFALSE; + if ((pTriInfos[t+1].iFlag&GROUP_WITH_ANY)!=0) bChooseOrientFirstTri = TTRUE; + else if ( CalcTexArea(pContext, &piTriListIn[t*3+0]) >= CalcTexArea(pContext, &piTriListIn[(t+1)*3+0]) ) + bChooseOrientFirstTri = TTRUE; + + // force match + { + const int t0 = bChooseOrientFirstTri ? t : (t+1); + const int t1 = bChooseOrientFirstTri ? (t+1) : t; + pTriInfos[t1].iFlag &= (~ORIENT_PRESERVING); // clear first + pTriInfos[t1].iFlag |= (pTriInfos[t0].iFlag&ORIENT_PRESERVING); // copy bit + } + } + } + t += 2; + } + else + ++t; + } + + // match up edge pairs + { + SEdge * pEdges = (SEdge *) malloc(sizeof(SEdge)*iNrTrianglesIn*3); + if (pEdges==NULL) + BuildNeighborsSlow(pTriInfos, piTriListIn, iNrTrianglesIn); + else + { + BuildNeighborsFast(pTriInfos, pEdges, piTriListIn, iNrTrianglesIn); + + free(pEdges); + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], const int iMyTriIndex, SGroup * pGroup); +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex); + +static int Build4RuleGroups(STriInfo pTriInfos[], SGroup pGroups[], int piGroupTrianglesBuffer[], const int piTriListIn[], const int iNrTrianglesIn) +{ + const int iNrMaxGroups = iNrTrianglesIn*3; + int iNrActiveGroups = 0; + int iOffset = 0, f=0, i=0; + (void)iNrMaxGroups; /* quiet warnings in non debug mode */ + for (f=0; f<iNrTrianglesIn; f++) + { + for (i=0; i<3; i++) + { + // if not assigned to a group + if ((pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 && pTriInfos[f].AssignedGroup[i]==NULL) + { + tbool bOrPre; + int neigh_indexL, neigh_indexR; + const int vert_index = piTriListIn[f*3+i]; + assert(iNrActiveGroups<iNrMaxGroups); + pTriInfos[f].AssignedGroup[i] = &pGroups[iNrActiveGroups]; + pTriInfos[f].AssignedGroup[i]->iVertexRepresentitive = vert_index; + pTriInfos[f].AssignedGroup[i]->bOrientPreservering = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0; + pTriInfos[f].AssignedGroup[i]->iNrFaces = 0; + pTriInfos[f].AssignedGroup[i]->pFaceIndices = &piGroupTrianglesBuffer[iOffset]; + ++iNrActiveGroups; + + AddTriToGroup(pTriInfos[f].AssignedGroup[i], f); + bOrPre = (pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + neigh_indexL = pTriInfos[f].FaceNeighbors[i]; + neigh_indexR = pTriInfos[f].FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexL, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexL].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + if (neigh_indexR>=0) // neighbor + { + const tbool bAnswer = + AssignRecur(piTriListIn, pTriInfos, neigh_indexR, + pTriInfos[f].AssignedGroup[i] ); + + const tbool bOrPre2 = (pTriInfos[neigh_indexR].iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + const tbool bDiff = bOrPre!=bOrPre2 ? TTRUE : TFALSE; + assert(bAnswer || bDiff); + (void)bAnswer, (void)bDiff; /* quiet warnings in non debug mode */ + } + + // update offset + iOffset += pTriInfos[f].AssignedGroup[i]->iNrFaces; + // since the groups are disjoint a triangle can never + // belong to more than 3 groups. Subsequently something + // is completely screwed if this assertion ever hits. + assert(iOffset <= iNrMaxGroups); + } + } + } + + return iNrActiveGroups; +} + +static void AddTriToGroup(SGroup * pGroup, const int iTriIndex) +{ + pGroup->pFaceIndices[pGroup->iNrFaces] = iTriIndex; + ++pGroup->iNrFaces; +} + +static tbool AssignRecur(const int piTriListIn[], STriInfo psTriInfos[], + const int iMyTriIndex, SGroup * pGroup) +{ + STriInfo * pMyTriInfo = &psTriInfos[iMyTriIndex]; + + // track down vertex + const int iVertRep = pGroup->iVertexRepresentitive; + const int * pVerts = &piTriListIn[3*iMyTriIndex+0]; + int i=-1; + if (pVerts[0]==iVertRep) i=0; + else if (pVerts[1]==iVertRep) i=1; + else if (pVerts[2]==iVertRep) i=2; + assert(i>=0 && i<3); + + // early out + if (pMyTriInfo->AssignedGroup[i] == pGroup) return TTRUE; + else if (pMyTriInfo->AssignedGroup[i]!=NULL) return TFALSE; + if ((pMyTriInfo->iFlag&GROUP_WITH_ANY)!=0) + { + // first to group with a group-with-anything triangle + // determines it's orientation. + // This is the only existing order dependency in the code!! + if ( pMyTriInfo->AssignedGroup[0] == NULL && + pMyTriInfo->AssignedGroup[1] == NULL && + pMyTriInfo->AssignedGroup[2] == NULL ) + { + pMyTriInfo->iFlag &= (~ORIENT_PRESERVING); + pMyTriInfo->iFlag |= (pGroup->bOrientPreservering ? ORIENT_PRESERVING : 0); + } + } + { + const tbool bOrient = (pMyTriInfo->iFlag&ORIENT_PRESERVING)!=0 ? TTRUE : TFALSE; + if (bOrient != pGroup->bOrientPreservering) return TFALSE; + } + + AddTriToGroup(pGroup, iMyTriIndex); + pMyTriInfo->AssignedGroup[i] = pGroup; + + { + const int neigh_indexL = pMyTriInfo->FaceNeighbors[i]; + const int neigh_indexR = pMyTriInfo->FaceNeighbors[i>0?(i-1):2]; + if (neigh_indexL>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexL, pGroup); + if (neigh_indexR>=0) + AssignRecur(piTriListIn, psTriInfos, neigh_indexR, pGroup); + } + + + + return TTRUE; +} + +///////////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////////////// + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2); +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed); +static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], const SMikkTSpaceContext * pContext, const int iVertexRepresentitive); + +static tbool GenerateTSpaces(STSpace psTspace[], const STriInfo pTriInfos[], const SGroup pGroups[], + const int iNrActiveGroups, const int piTriListIn[], const float fThresCos, + const SMikkTSpaceContext * pContext) +{ + STSpace * pSubGroupTspace = NULL; + SSubGroup * pUniSubGroups = NULL; + int * pTmpMembers = NULL; + int iMaxNrFaces=0, iUniqueTspaces=0, g=0, i=0; + for (g=0; g<iNrActiveGroups; g++) + if (iMaxNrFaces < pGroups[g].iNrFaces) + iMaxNrFaces = pGroups[g].iNrFaces; + + if (iMaxNrFaces == 0) return TTRUE; + + // make initial allocations + pSubGroupTspace = (STSpace *) malloc(sizeof(STSpace)*iMaxNrFaces); + pUniSubGroups = (SSubGroup *) malloc(sizeof(SSubGroup)*iMaxNrFaces); + pTmpMembers = (int *) malloc(sizeof(int)*iMaxNrFaces); + if (pSubGroupTspace==NULL || pUniSubGroups==NULL || pTmpMembers==NULL) + { + if (pSubGroupTspace!=NULL) free(pSubGroupTspace); + if (pUniSubGroups!=NULL) free(pUniSubGroups); + if (pTmpMembers!=NULL) free(pTmpMembers); + return TFALSE; + } + + + iUniqueTspaces = 0; + for (g=0; g<iNrActiveGroups; g++) + { + const SGroup * pGroup = &pGroups[g]; + int iUniqueSubGroups = 0, s=0; + + for (i=0; i<pGroup->iNrFaces; i++) // triangles + { + const int f = pGroup->pFaceIndices[i]; // triangle number + int index=-1, iVertIndex=-1, iOF_1=-1, iMembers=0, j=0, l=0; + SSubGroup tmp_group; + tbool bFound; + SVec3 n, vOs, vOt; + if (pTriInfos[f].AssignedGroup[0]==pGroup) index=0; + else if (pTriInfos[f].AssignedGroup[1]==pGroup) index=1; + else if (pTriInfos[f].AssignedGroup[2]==pGroup) index=2; + assert(index>=0 && index<3); + + iVertIndex = piTriListIn[f*3+index]; + assert(iVertIndex==pGroup->iVertexRepresentitive); + + // is normalized already + n = GetNormal(pContext, iVertIndex); + + // project + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + // original face number + iOF_1 = pTriInfos[f].iOrgFaceNumber; + + iMembers = 0; + for (j=0; j<pGroup->iNrFaces; j++) + { + const int t = pGroup->pFaceIndices[j]; // triangle number + const int iOF_2 = pTriInfos[t].iOrgFaceNumber; + + // project + SVec3 vOs2 = vsub(pTriInfos[t].vOs, vscale(vdot(n,pTriInfos[t].vOs), n)); + SVec3 vOt2 = vsub(pTriInfos[t].vOt, vscale(vdot(n,pTriInfos[t].vOt), n)); + if ( VNotZero(vOs2) ) vOs2 = Normalize(vOs2); + if ( VNotZero(vOt2) ) vOt2 = Normalize(vOt2); + + { + const tbool bAny = ( (pTriInfos[f].iFlag | pTriInfos[t].iFlag) & GROUP_WITH_ANY )!=0 ? TTRUE : TFALSE; + // make sure triangles which belong to the same quad are joined. + const tbool bSameOrgFace = iOF_1==iOF_2 ? TTRUE : TFALSE; + + const float fCosS = vdot(vOs,vOs2); + const float fCosT = vdot(vOt,vOt2); + + assert(f!=t || bSameOrgFace); // sanity check + if (bAny || bSameOrgFace || (fCosS>fThresCos && fCosT>fThresCos)) + pTmpMembers[iMembers++] = t; + } + } + + // sort pTmpMembers + tmp_group.iNrFaces = iMembers; + tmp_group.pTriMembers = pTmpMembers; + if (iMembers>1) + { + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + QuickSort(pTmpMembers, 0, iMembers-1, uSeed); + } + + // look for an existing match + bFound = TFALSE; + l=0; + while (l<iUniqueSubGroups && !bFound) + { + bFound = CompareSubGroups(&tmp_group, &pUniSubGroups[l]); + if (!bFound) ++l; + } + + // assign tangent space index + assert(bFound || l==iUniqueSubGroups); + //piTempTangIndices[f*3+index] = iUniqueTspaces+l; + + // if no match was found we allocate a new subgroup + if (!bFound) + { + // insert new subgroup + int * pIndices = (int *) malloc(sizeof(int)*iMembers); + if (pIndices==NULL) + { + // clean up and return false + int s=0; + for (s=0; s<iUniqueSubGroups; s++) + free(pUniSubGroups[s].pTriMembers); + free(pUniSubGroups); + free(pTmpMembers); + free(pSubGroupTspace); + return TFALSE; + } + pUniSubGroups[iUniqueSubGroups].iNrFaces = iMembers; + pUniSubGroups[iUniqueSubGroups].pTriMembers = pIndices; + memcpy(pIndices, tmp_group.pTriMembers, iMembers*sizeof(int)); + pSubGroupTspace[iUniqueSubGroups] = + EvalTspace(tmp_group.pTriMembers, iMembers, piTriListIn, pTriInfos, pContext, pGroup->iVertexRepresentitive); + ++iUniqueSubGroups; + } + + // output tspace + { + const int iOffs = pTriInfos[f].iTSpacesOffs; + const int iVert = pTriInfos[f].vert_num[index]; + STSpace * pTS_out = &psTspace[iOffs+iVert]; + assert(pTS_out->iCounter<2); + assert(((pTriInfos[f].iFlag&ORIENT_PRESERVING)!=0) == pGroup->bOrientPreservering); + if (pTS_out->iCounter==1) + { + *pTS_out = AvgTSpace(pTS_out, &pSubGroupTspace[l]); + pTS_out->iCounter = 2; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + else + { + assert(pTS_out->iCounter==0); + *pTS_out = pSubGroupTspace[l]; + pTS_out->iCounter = 1; // update counter + pTS_out->bOrient = pGroup->bOrientPreservering; + } + } + } + + // clean up and offset iUniqueTspaces + for (s=0; s<iUniqueSubGroups; s++) + free(pUniSubGroups[s].pTriMembers); + iUniqueTspaces += iUniqueSubGroups; + } + + // clean up + free(pUniSubGroups); + free(pTmpMembers); + free(pSubGroupTspace); + + return TTRUE; +} + +static STSpace EvalTspace(int face_indices[], const int iFaces, const int piTriListIn[], const STriInfo pTriInfos[], + const SMikkTSpaceContext * pContext, const int iVertexRepresentitive) +{ + STSpace res; + float fAngleSum = 0; + int face=0; + res.vOs.x=0.0f; res.vOs.y=0.0f; res.vOs.z=0.0f; + res.vOt.x=0.0f; res.vOt.y=0.0f; res.vOt.z=0.0f; + res.fMagS = 0; res.fMagT = 0; + + for (face=0; face<iFaces; face++) + { + const int f = face_indices[face]; + + // only valid triangles get to add their contribution + if ( (pTriInfos[f].iFlag&GROUP_WITH_ANY)==0 ) + { + SVec3 n, vOs, vOt, p0, p1, p2, v1, v2; + float fCos, fAngle, fMagS, fMagT; + int i=-1, index=-1, i0=-1, i1=-1, i2=-1; + if (piTriListIn[3*f+0]==iVertexRepresentitive) i=0; + else if (piTriListIn[3*f+1]==iVertexRepresentitive) i=1; + else if (piTriListIn[3*f+2]==iVertexRepresentitive) i=2; + assert(i>=0 && i<3); + + // project + index = piTriListIn[3*f+i]; + n = GetNormal(pContext, index); + vOs = vsub(pTriInfos[f].vOs, vscale(vdot(n,pTriInfos[f].vOs), n)); + vOt = vsub(pTriInfos[f].vOt, vscale(vdot(n,pTriInfos[f].vOt), n)); + if ( VNotZero(vOs) ) vOs = Normalize(vOs); + if ( VNotZero(vOt) ) vOt = Normalize(vOt); + + i2 = piTriListIn[3*f + (i<2?(i+1):0)]; + i1 = piTriListIn[3*f + i]; + i0 = piTriListIn[3*f + (i>0?(i-1):2)]; + + p0 = GetPosition(pContext, i0); + p1 = GetPosition(pContext, i1); + p2 = GetPosition(pContext, i2); + v1 = vsub(p0,p1); + v2 = vsub(p2,p1); + + // project + v1 = vsub(v1, vscale(vdot(n,v1),n)); if ( VNotZero(v1) ) v1 = Normalize(v1); + v2 = vsub(v2, vscale(vdot(n,v2),n)); if ( VNotZero(v2) ) v2 = Normalize(v2); + + // weight contribution by the angle + // between the two edge vectors + fCos = vdot(v1,v2); fCos=fCos>1?1:(fCos<(-1) ? (-1) : fCos); + fAngle = (float) acos(fCos); + fMagS = pTriInfos[f].fMagS; + fMagT = pTriInfos[f].fMagT; + + res.vOs=vadd(res.vOs, vscale(fAngle,vOs)); + res.vOt=vadd(res.vOt,vscale(fAngle,vOt)); + res.fMagS+=(fAngle*fMagS); + res.fMagT+=(fAngle*fMagT); + fAngleSum += fAngle; + } + } + + // normalize + if ( VNotZero(res.vOs) ) res.vOs = Normalize(res.vOs); + if ( VNotZero(res.vOt) ) res.vOt = Normalize(res.vOt); + if (fAngleSum>0) + { + res.fMagS /= fAngleSum; + res.fMagT /= fAngleSum; + } + + return res; +} + +static tbool CompareSubGroups(const SSubGroup * pg1, const SSubGroup * pg2) +{ + tbool bStillSame=TTRUE; + int i=0; + if (pg1->iNrFaces!=pg2->iNrFaces) return TFALSE; + while (i<pg1->iNrFaces && bStillSame) + { + bStillSame = pg1->pTriMembers[i]==pg2->pTriMembers[i] ? TTRUE : TFALSE; + if (bStillSame) ++i; + } + return bStillSame; +} + +static void QuickSort(int* pSortBuffer, int iLeft, int iRight, unsigned int uSeed) +{ + int iL, iR, n, index, iMid, iTmp; + + // Random + unsigned int t=uSeed&31; + t=(uSeed<<t)|(uSeed>>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL=iLeft; iR=iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL]; + + + do + { + while (pSortBuffer[iL] < iMid) + ++iL; + while (pSortBuffer[iR] > iMid) + --iR; + + if (iL <= iR) + { + iTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = iTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSort(pSortBuffer, iLeft, iR, uSeed); + if (iL < iRight) + QuickSort(pSortBuffer, iL, iRight, uSeed); +} + +///////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////////////////////// + +static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed); +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in); + +static void BuildNeighborsFast(STriInfo pTriInfos[], SEdge * pEdges, const int piTriListIn[], const int iNrTrianglesIn) +{ + // build array of edges + unsigned int uSeed = INTERNAL_RND_SORT_SEED; // could replace with a random seed? + int iEntries=0, iCurStartIndex=-1, f=0, i=0; + for (f=0; f<iNrTrianglesIn; f++) + for (i=0; i<3; i++) + { + const int i0 = piTriListIn[f*3+i]; + const int i1 = piTriListIn[f*3+(i<2?(i+1):0)]; + pEdges[f*3+i].i0 = i0 < i1 ? i0 : i1; // put minimum index in i0 + pEdges[f*3+i].i1 = !(i0 < i1) ? i0 : i1; // put maximum index in i1 + pEdges[f*3+i].f = f; // record face number + } + + // sort over all edges by i0, this is the pricy one. + QuickSortEdges(pEdges, 0, iNrTrianglesIn*3-1, 0, uSeed); // sort channel 0 which is i0 + + // sub sort over i1, should be fast. + // could replace this with a 64 bit int sort over (i0,i1) + // with i0 as msb in the quicksort call above. + iEntries = iNrTrianglesIn*3; + iCurStartIndex = 0; + for (i=1; i<iEntries; i++) + { + if (pEdges[iCurStartIndex].i0 != pEdges[i].i0) + { + const int iL = iCurStartIndex; + const int iR = i-1; + //const int iElems = i-iL; + iCurStartIndex = i; + QuickSortEdges(pEdges, iL, iR, 1, uSeed); // sort channel 1 which is i1 + } + } + + // sub sort over f, which should be fast. + // this step is to remain compliant with BuildNeighborsSlow() when + // more than 2 triangles use the same edge (such as a butterfly topology). + iCurStartIndex = 0; + for (i=1; i<iEntries; i++) + { + if (pEdges[iCurStartIndex].i0 != pEdges[i].i0 || pEdges[iCurStartIndex].i1 != pEdges[i].i1) + { + const int iL = iCurStartIndex; + const int iR = i-1; + //const int iElems = i-iL; + iCurStartIndex = i; + QuickSortEdges(pEdges, iL, iR, 2, uSeed); // sort channel 2 which is f + } + } + + // pair up, adjacent triangles + for (i=0; i<iEntries; i++) + { + const int i0=pEdges[i].i0; + const int i1=pEdges[i].i1; + const int f = pEdges[i].f; + tbool bUnassigned_A; + + int i0_A, i1_A; + int edgenum_A, edgenum_B=0; // 0,1 or 2 + GetEdge(&i0_A, &i1_A, &edgenum_A, &piTriListIn[f*3], i0, i1); // resolve index ordering and edge_num + bUnassigned_A = pTriInfos[f].FaceNeighbors[edgenum_A] == -1 ? TTRUE : TFALSE; + + if (bUnassigned_A) + { + // get true index ordering + int j=i+1, t; + tbool bNotFound = TTRUE; + while (j<iEntries && i0==pEdges[j].i0 && i1==pEdges[j].i1 && bNotFound) + { + tbool bUnassigned_B; + int i0_B, i1_B; + t = pEdges[j].f; + // flip i0_B and i1_B + GetEdge(&i1_B, &i0_B, &edgenum_B, &piTriListIn[t*3], pEdges[j].i0, pEdges[j].i1); // resolve index ordering and edge_num + //assert(!(i0_A==i1_B && i1_A==i0_B)); + bUnassigned_B = pTriInfos[t].FaceNeighbors[edgenum_B]==-1 ? TTRUE : TFALSE; + if (i0_A==i0_B && i1_A==i1_B && bUnassigned_B) + bNotFound = TFALSE; + else + ++j; + } + + if (!bNotFound) + { + int t = pEdges[j].f; + pTriInfos[f].FaceNeighbors[edgenum_A] = t; + //assert(pTriInfos[t].FaceNeighbors[edgenum_B]==-1); + pTriInfos[t].FaceNeighbors[edgenum_B] = f; + } + } + } +} + +static void BuildNeighborsSlow(STriInfo pTriInfos[], const int piTriListIn[], const int iNrTrianglesIn) +{ + int f=0, i=0; + for (f=0; f<iNrTrianglesIn; f++) + { + for (i=0; i<3; i++) + { + // if unassigned + if (pTriInfos[f].FaceNeighbors[i] == -1) + { + const int i0_A = piTriListIn[f*3+i]; + const int i1_A = piTriListIn[f*3+(i<2?(i+1):0)]; + + // search for a neighbor + tbool bFound = TFALSE; + int t=0, j=0; + while (!bFound && t<iNrTrianglesIn) + { + if (t!=f) + { + j=0; + while (!bFound && j<3) + { + // in rev order + const int i1_B = piTriListIn[t*3+j]; + const int i0_B = piTriListIn[t*3+(j<2?(j+1):0)]; + //assert(!(i0_A==i1_B && i1_A==i0_B)); + if (i0_A==i0_B && i1_A==i1_B) + bFound = TTRUE; + else + ++j; + } + } + + if (!bFound) ++t; + } + + // assign neighbors + if (bFound) + { + pTriInfos[f].FaceNeighbors[i] = t; + //assert(pTriInfos[t].FaceNeighbors[j]==-1); + pTriInfos[t].FaceNeighbors[j] = f; + } + } + } + } +} + +static void QuickSortEdges(SEdge * pSortBuffer, int iLeft, int iRight, const int channel, unsigned int uSeed) +{ + unsigned int t; + int iL, iR, n, index, iMid; + + // early out + SEdge sTmp; + const int iElems = iRight-iLeft+1; + if (iElems<2) return; + else if (iElems==2) + { + if (pSortBuffer[iLeft].array[channel] > pSortBuffer[iRight].array[channel]) + { + sTmp = pSortBuffer[iLeft]; + pSortBuffer[iLeft] = pSortBuffer[iRight]; + pSortBuffer[iRight] = sTmp; + } + return; + } + + // Random + t=uSeed&31; + t=(uSeed<<t)|(uSeed>>(32-t)); + uSeed=uSeed+t+3; + // Random end + + iL=iLeft, iR=iRight; + n = (iR-iL)+1; + assert(n>=0); + index = (int) (uSeed%n); + + iMid=pSortBuffer[index + iL].array[channel]; + + do + { + while (pSortBuffer[iL].array[channel] < iMid) + ++iL; + while (pSortBuffer[iR].array[channel] > iMid) + --iR; + + if (iL <= iR) + { + sTmp = pSortBuffer[iL]; + pSortBuffer[iL] = pSortBuffer[iR]; + pSortBuffer[iR] = sTmp; + ++iL; --iR; + } + } + while (iL <= iR); + + if (iLeft < iR) + QuickSortEdges(pSortBuffer, iLeft, iR, channel, uSeed); + if (iL < iRight) + QuickSortEdges(pSortBuffer, iL, iRight, channel, uSeed); +} + +// resolve ordering and edge number +static void GetEdge(int * i0_out, int * i1_out, int * edgenum_out, const int indices[], const int i0_in, const int i1_in) +{ + *edgenum_out = -1; + + // test if first index is on the edge + if (indices[0]==i0_in || indices[0]==i1_in) + { + // test if second index is on the edge + if (indices[1]==i0_in || indices[1]==i1_in) + { + edgenum_out[0]=0; // first edge + i0_out[0]=indices[0]; + i1_out[0]=indices[1]; + } + else + { + edgenum_out[0]=2; // third edge + i0_out[0]=indices[2]; + i1_out[0]=indices[0]; + } + } + else + { + // only second and third index is on the edge + edgenum_out[0]=1; // second edge + i0_out[0]=indices[1]; + i1_out[0]=indices[2]; + } +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Degenerate triangles //////////////////////////////////// + +static void DegenPrologue(STriInfo pTriInfos[], int piTriList_out[], const int iNrTrianglesIn, const int iTotTris) +{ + int iNextGoodTriangleSearchIndex=-1; + tbool bStillFindingGoodOnes; + + // locate quads with only one good triangle + int t=0; + while (t<(iTotTris-1)) + { + const int iFO_a = pTriInfos[t].iOrgFaceNumber; + const int iFO_b = pTriInfos[t+1].iOrgFaceNumber; + if (iFO_a==iFO_b) // this is a quad + { + const tbool bIsDeg_a = (pTriInfos[t].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + const tbool bIsDeg_b = (pTriInfos[t+1].iFlag&MARK_DEGENERATE)!=0 ? TTRUE : TFALSE; + if ((bIsDeg_a^bIsDeg_b)!=0) + { + pTriInfos[t].iFlag |= QUAD_ONE_DEGEN_TRI; + pTriInfos[t+1].iFlag |= QUAD_ONE_DEGEN_TRI; + } + t += 2; + } + else + ++t; + } + + // reorder list so all degen triangles are moved to the back + // without reordering the good triangles + iNextGoodTriangleSearchIndex = 1; + t=0; + bStillFindingGoodOnes = TTRUE; + while (t<iNrTrianglesIn && bStillFindingGoodOnes) + { + const tbool bIsGood = (pTriInfos[t].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE; + if (bIsGood) + { + if (iNextGoodTriangleSearchIndex < (t+2)) + iNextGoodTriangleSearchIndex = t+2; + } + else + { + int t0, t1; + // search for the first good triangle. + tbool bJustADegenerate = TTRUE; + while (bJustADegenerate && iNextGoodTriangleSearchIndex<iTotTris) + { + const tbool bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag&MARK_DEGENERATE)==0 ? TTRUE : TFALSE; + if (bIsGood) bJustADegenerate=TFALSE; + else ++iNextGoodTriangleSearchIndex; + } + + t0 = t; + t1 = iNextGoodTriangleSearchIndex; + ++iNextGoodTriangleSearchIndex; + assert(iNextGoodTriangleSearchIndex > (t+1)); + + // swap triangle t0 and t1 + if (!bJustADegenerate) + { + int i=0; + for (i=0; i<3; i++) + { + const int index = piTriList_out[t0*3+i]; + piTriList_out[t0*3+i] = piTriList_out[t1*3+i]; + piTriList_out[t1*3+i] = index; + } + { + const STriInfo tri_info = pTriInfos[t0]; + pTriInfos[t0] = pTriInfos[t1]; + pTriInfos[t1] = tri_info; + } + } + else + bStillFindingGoodOnes = TFALSE; // this is not supposed to happen + } + + if (bStillFindingGoodOnes) ++t; + } + + assert(bStillFindingGoodOnes); // code will still work. + assert(iNrTrianglesIn == t); +} + +static void DegenEpilogue(STSpace psTspace[], STriInfo pTriInfos[], int piTriListIn[], const SMikkTSpaceContext * pContext, const int iNrTrianglesIn, const int iTotTris) +{ + int t=0, i=0; + // deal with degenerate triangles + // punishment for degenerate triangles is O(N^2) + for (t=iNrTrianglesIn; t<iTotTris; t++) + { + // degenerate triangles on a quad with one good triangle are skipped + // here but processed in the next loop + const tbool bSkip = (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ? TTRUE : TFALSE; + + if (!bSkip) + { + for (i=0; i<3; i++) + { + const int index1 = piTriListIn[t*3+i]; + // search through the good triangles + tbool bNotFound = TTRUE; + int j=0; + while (bNotFound && j<(3*iNrTrianglesIn)) + { + const int index2 = piTriListIn[j]; + if (index1==index2) bNotFound=TFALSE; + else ++j; + } + + if (!bNotFound) + { + const int iTri = j/3; + const int iVert = j%3; + const int iSrcVert=pTriInfos[iTri].vert_num[iVert]; + const int iSrcOffs=pTriInfos[iTri].iTSpacesOffs; + const int iDstVert=pTriInfos[t].vert_num[i]; + const int iDstOffs=pTriInfos[t].iTSpacesOffs; + + // copy tspace + psTspace[iDstOffs+iDstVert] = psTspace[iSrcOffs+iSrcVert]; + } + } + } + } + + // deal with degenerate quads with one good triangle + for (t=0; t<iNrTrianglesIn; t++) + { + // this triangle belongs to a quad where the + // other triangle is degenerate + if ( (pTriInfos[t].iFlag&QUAD_ONE_DEGEN_TRI)!=0 ) + { + SVec3 vDstP; + int iOrgF=-1, i=0; + tbool bNotFound; + unsigned char * pV = pTriInfos[t].vert_num; + int iFlag = (1<<pV[0]) | (1<<pV[1]) | (1<<pV[2]); + int iMissingIndex = 0; + if ((iFlag&2)==0) iMissingIndex=1; + else if ((iFlag&4)==0) iMissingIndex=2; + else if ((iFlag&8)==0) iMissingIndex=3; + + iOrgF = pTriInfos[t].iOrgFaceNumber; + vDstP = GetPosition(pContext, MakeIndex(iOrgF, iMissingIndex)); + bNotFound = TTRUE; + i=0; + while (bNotFound && i<3) + { + const int iVert = pV[i]; + const SVec3 vSrcP = GetPosition(pContext, MakeIndex(iOrgF, iVert)); + if (veq(vSrcP, vDstP)==TTRUE) + { + const int iOffs = pTriInfos[t].iTSpacesOffs; + psTspace[iOffs+iMissingIndex] = psTspace[iOffs+iVert]; + bNotFound=TFALSE; + } + else + ++i; + } + assert(!bNotFound); + } + } +} diff --git a/scene/resources/mikktspace.h b/scene/resources/mikktspace.h new file mode 100644 index 0000000000..52c44a713c --- /dev/null +++ b/scene/resources/mikktspace.h @@ -0,0 +1,145 @@ +/** \file mikktspace/mikktspace.h + * \ingroup mikktspace + */ +/** + * Copyright (C) 2011 by Morten S. Mikkelsen + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + */ + +#ifndef __MIKKTSPACE_H__ +#define __MIKKTSPACE_H__ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Author: Morten S. Mikkelsen + * Version: 1.0 + * + * The files mikktspace.h and mikktspace.c are designed to be + * stand-alone files and it is important that they are kept this way. + * Not having dependencies on structures/classes/libraries specific + * to the program, in which they are used, allows them to be copied + * and used as is into any tool, program or plugin. + * The code is designed to consistently generate the same + * tangent spaces, for a given mesh, in any tool in which it is used. + * This is done by performing an internal welding step and subsequently an order-independent evaluation + * of tangent space for meshes consisting of triangles and quads. + * This means faces can be received in any order and the same is true for + * the order of vertices of each face. The generated result will not be affected + * by such reordering. Additionally, whether degenerate (vertices or texture coordinates) + * primitives are present or not will not affect the generated results either. + * Once tangent space calculation is done the vertices of degenerate primitives will simply + * inherit tangent space from neighboring non degenerate primitives. + * The analysis behind this implementation can be found in my master's thesis + * which is available for download --> http://image.diku.dk/projects/media/morten.mikkelsen.08.pdf + * Note that though the tangent spaces at the vertices are generated in an order-independent way, + * by this implementation, the interpolated tangent space is still affected by which diagonal is + * chosen to split each quad. A sensible solution is to have your tools pipeline always + * split quads by the shortest diagonal. This choice is order-independent and works with mirroring. + * If these have the same length then compare the diagonals defined by the texture coordinates. + * XNormal which is a tool for baking normal maps allows you to write your own tangent space plugin + * and also quad triangulator plugin. + */ + + +typedef int tbool; +typedef struct SMikkTSpaceContext SMikkTSpaceContext; + +typedef struct { + // Returns the number of faces (triangles/quads) on the mesh to be processed. + int (*m_getNumFaces)(const SMikkTSpaceContext * pContext); + + // Returns the number of vertices on face number iFace + // iFace is a number in the range {0, 1, ..., getNumFaces()-1} + int (*m_getNumVerticesOfFace)(const SMikkTSpaceContext * pContext, const int iFace); + + // returns the position/normal/texcoord of the referenced face of vertex number iVert. + // iVert is in the range {0,1,2} for triangles and {0,1,2,3} for quads. + void (*m_getPosition)(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + void (*m_getNormal)(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + void (*m_getTexCoord)(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + + // either (or both) of the two setTSpace callbacks can be set. + // The call-back m_setTSpaceBasic() is sufficient for basic normal mapping. + + // This function is used to return the tangent and fSign to the application. + // fvTangent is a unit length vector. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpaceBasic)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); + + // This function is used to return tangent space results to the application. + // fvTangent and fvBiTangent are unit length vectors and fMagS and fMagT are their + // true magnitudes which can be used for relief mapping effects. + // fvBiTangent is the "real" bitangent and thus may not be perpendicular to fvTangent. + // However, both are perpendicular to the vertex normal. + // For normal maps it is sufficient to use the following simplified version of the bitangent which is generated at pixel/vertex level. + // fSign = bIsOrientationPreserving ? 1.0f : (-1.0f); + // bitangent = fSign * cross(vN, tangent); + // Note that the results are returned unindexed. It is possible to generate a new index list + // But averaging/overwriting tangent spaces by using an already existing index list WILL produce INCRORRECT results. + // DO NOT! use an already existing index list. + void (*m_setTSpace)(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fvBiTangent[], const float fMagS, const float fMagT, + const tbool bIsOrientationPreserving, const int iFace, const int iVert); +} SMikkTSpaceInterface; + +struct SMikkTSpaceContext +{ + SMikkTSpaceInterface * m_pInterface; // initialized with callback functions + void * m_pUserData; // pointer to client side mesh data etc. (passed as the first parameter with every interface call) +}; + +// these are both thread safe! +tbool genTangSpaceDefault(const SMikkTSpaceContext * pContext); // Default (recommended) fAngularThreshold is 180 degrees (which means threshold disabled) +tbool genTangSpace(const SMikkTSpaceContext * pContext, const float fAngularThreshold); + + +// To avoid visual errors (distortions/unwanted hard edges in lighting), when using sampled normal maps, the +// normal map sampler must use the exact inverse of the pixel shader transformation. +// The most efficient transformation we can possibly do in the pixel shader is +// achieved by using, directly, the "unnormalized" interpolated tangent, bitangent and vertex normal: vT, vB and vN. +// pixel shader (fast transform out) +// vNout = normalize( vNt.x * vT + vNt.y * vB + vNt.z * vN ); +// where vNt is the tangent space normal. The normal map sampler must likewise use the +// interpolated and "unnormalized" tangent, bitangent and vertex normal to be compliant with the pixel shader. +// sampler does (exact inverse of pixel shader): +// float3 row0 = cross(vB, vN); +// float3 row1 = cross(vN, vT); +// float3 row2 = cross(vT, vB); +// float fSign = dot(vT, row0)<0 ? -1 : 1; +// vNt = normalize( fSign * float3(dot(vNout,row0), dot(vNout,row1), dot(vNout,row2)) ); +// where vNout is the sampled normal in some chosen 3D space. +// +// Should you choose to reconstruct the bitangent in the pixel shader instead +// of the vertex shader, as explained earlier, then be sure to do this in the normal map sampler also. +// Finally, beware of quad triangulations. If the normal map sampler doesn't use the same triangulation of +// quads as your renderer then problems will occur since the interpolated tangent spaces will differ +// eventhough the vertex level tangent spaces match. This can be solved either by triangulating before +// sampling/exporting or by using the order-independent choice of diagonal for splitting quads suggested earlier. +// However, this must be used both by the sampler and your tools/rendering pipeline. + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 3bd7314778..5883686f20 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -29,6 +29,9 @@ #include "packed_scene.h" #include "globals.h" #include "io/resource_loader.h" +#include "scene/3d/spatial.h" +#include "scene/gui/control.h" +#include "scene/2d/node_2d.h" bool PackedScene::can_instance() const { @@ -80,9 +83,28 @@ Node *PackedScene::instance(bool p_gen_edit_state) const { } else { //create anew Object * obj = ObjectTypeDB::instance(snames[ n.type ]); - ERR_FAIL_COND_V(!obj,NULL); + if (!obj || !obj->cast_to<Node>()) { + if (obj) { + memdelete(obj); + obj=NULL; + } + WARN_PRINT(String("Warning node of type "+snames[n.type].operator String()+" does not exist.").ascii().get_data()); + if (n.parent>=0 && n.parent<nc && ret_nodes[n.parent]) { + if (ret_nodes[n.parent]->cast_to<Spatial>()) { + obj = memnew( Spatial ); + } else if (ret_nodes[n.parent]->cast_to<Control>()) { + obj = memnew( Control ); + } else if (ret_nodes[n.parent]->cast_to<Node2D>()) { + obj = memnew( Node2D ); + } + + } + if (!obj) { + obj = memnew( Node ); + } + } + node = obj->cast_to<Node>(); - ERR_FAIL_COND_V(!node,NULL); } @@ -225,22 +247,38 @@ Error PackedScene::_parse_node(Node *p_owner,Node *p_node,int p_parent_idx, Map< p_node->get_property_list(&plist); for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) { continue; + } 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()) + if (E->get().usage & PROPERTY_USAGE_STORE_IF_NONZERO && value.is_zero()) { continue; + } if (nd.instance>=0) { //only save changed properties in instance - if (!instance_state.has(name)) + /* + // 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"); + continue; + }*/ + + if (E->get().usage & PROPERTY_USAGE_NO_INSTANCE_STATE) { continue; - if (instance_state[name]==value) + } + + if (instance_state[name]==value) { continue; + } } diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp index afb0ae1815..9f691d6ad3 100644 --- a/scene/resources/polygon_path_finder.cpp +++ b/scene/resources/polygon_path_finder.cpp @@ -142,6 +142,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector if (d<closest_dist) { ignore_from_edge=E->get(); closest_dist=d; + closest_point=closest; } } @@ -168,6 +169,7 @@ Vector<Vector2> PolygonPathFinder::find_path(const Vector2& p_from, const Vector if (d<closest_dist) { ignore_to_edge=E->get(); closest_dist=d; + closest_point=closest; } } @@ -529,7 +531,7 @@ Vector2 PolygonPathFinder::get_closest_point(const Vector2& p_point) const { float d = p_point.distance_squared_to(points[i].pos); if (d<closest_dist) { - d=closest_dist; + closest_dist=d; closest_idx=i; } diff --git a/scene/resources/scene_preloader.cpp b/scene/resources/scene_preloader.cpp index 59d8cae970..e37a2c4967 100644 --- a/scene/resources/scene_preloader.cpp +++ b/scene/resources/scene_preloader.cpp @@ -26,430 +26,429 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "scene_preloader.h"
-#include "scene/io/scene_loader.h"
-#include "globals.h"
-
-bool ScenePreloader::can_instance() const {
-
- return nodes.size()>0;
-}
-
-Node *ScenePreloader::instance() const {
-
- int nc = nodes.size();
- ERR_FAIL_COND_V(nc==0,NULL);
-
- const StringName*snames=NULL;
- int sname_count=names.size();
- if (sname_count)
- snames=&names[0];
-
- const Variant*props=NULL;
- int prop_count=variants.size();
- if (prop_count)
- props=&variants[0];
-
- Vector<Variant> properties;
-
- const NodeData *nd = &nodes[0];
-
- Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc );
-
- 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;
- }
-
- Object * obj = ObjectTypeDB::instance(snames[ n.type ]);
- ERR_FAIL_COND_V(!obj,NULL);
- Node *node = obj->cast_to<Node>();
- ERR_FAIL_COND_V(!node,NULL);
-
- int nprop_count=n.properties.size();
- if (nprop_count) {
-
- const NodeData::Property* nprops=&n.properties[0];
-
- for(int j=0;j<nprop_count;j++) {
-
- bool valid;
- node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid);
- }
-
-
- }
-
- node->set_name( 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(node);
- }
- }
-
-
- //do connections
-
- int cc = connections.size();
- const ConnectionData *cdata = connections.ptr();
-
- 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 );
-
- Vector<Variant> binds;
- if (c.binds.size()) {
- binds.resize(c.binds.size());
- for(int j=0;j<c.binds.size();j++)
- 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 );
- }
-
- return ret_nodes[0];
-
-}
-
-
-static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) {
-
- if (name_map.has(p_string))
- return name_map[p_string];
-
- int idx = name_map.size();
- name_map[p_string]=idx;
- return idx;
-}
-
-static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) {
-
- if (variant_map.has(p_variant))
- return variant_map[p_variant];
-
- int idx = variant_map.size();
- variant_map[p_variant]=idx;
- return idx;
-}
-
-void ScenePreloader::_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) {
-
- if (p_node!=p_owner && !p_node->get_owner())
- return;
-
- 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;
-
- List<PropertyInfo> plist;
- p_node->get_property_list(&plist);
- for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) {
-
- if (!(E->get().usage & PROPERTY_USAGE_STORAGE))
- continue;
-
- NodeData::Property prop;
- prop.name=_nm_get_string(E->get().name,name_map);
- prop.value=_vm_get_variant( p_node->get( E->get().name ), variant_map);
- nd.properties.push_back(prop);
- }
-
- int idx = nodes.size();
- node_map[p_node]=idx;
- nodes.push_back(nd);
-
- for(int i=0;i<p_node->get_child_count();i++) {
-
- Node *c=p_node->get_child(i);
- _parse_node(p_owner,c,idx,name_map,variant_map,node_map);
- }
-
-
-
-}
-
-void ScenePreloader::_parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance) {
-
-
- List<MethodInfo> signals;
- p_node->get_signal_list(&signals);
-
- 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))
- continue;
- Node *n=c.target->cast_to<Node>();
- if (!n)
- continue;
-
- if (!node_map.has(n))
- continue;
-
- ConnectionData cd;
- cd.from=node_map[p_node];
- cd.to=node_map[n];
- cd.method=_nm_get_string(c.method,name_map);
- cd.signal=_nm_get_string(c.signal,name_map);
- for(int i=0;i<c.binds.size();i++) {
-
- cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map));
- }
- connections.push_back(cd);
- }
- }
-
-}
-
-
-Error ScenePreloader::load_scene(const String& p_path) {
-
- return ERR_CANT_OPEN;
-#if 0
- if (path==p_path)
- return OK;
-
- String p=Globals::get_singleton()->localize_path(p_path);
- clear();
-
- Node *scene = SceneLoader::load(p);
-
- ERR_FAIL_COND_V(!scene,ERR_CANT_OPEN);
-
- path=p;
-
- Map<StringName,int> name_map;
- HashMap<Variant,int,VariantHasher> variant_map;
- Map<Node*,int> node_map;
-
- _parse_node(scene,scene,-1,name_map,variant_map,node_map);
-
-
- names.resize(name_map.size());
-
- for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) {
-
- names[E->get()]=E->key();
- }
-
- variants.resize(variant_map.size());
- const Variant *K=NULL;
- while((K=variant_map.next(K))) {
-
- int idx = variant_map[*K];
- variants[idx]=*K;
- }
-
-
- memdelete(scene); // <- me falto esto :(
- return OK;
-#endif
-}
-
-String ScenePreloader::get_scene_path() const {
-
- return path;
-}
-
-void ScenePreloader::clear() {
-
- names.clear();
- variants.clear();
- nodes.clear();
- connections.clear();
-
-}
-
-void ScenePreloader::_set_bundled_scene(const Dictionary& d) {
-
-
- ERR_FAIL_COND( !d.has("names"));
- ERR_FAIL_COND( !d.has("variants"));
- ERR_FAIL_COND( !d.has("node_count"));
- ERR_FAIL_COND( !d.has("nodes"));
- ERR_FAIL_COND( !d.has("conn_count"));
- ERR_FAIL_COND( !d.has("conns"));
- ERR_FAIL_COND( !d.has("path"));
-
- DVector<String> snames = d["names"];
- if (snames.size()) {
-
- int namecount = snames.size();
- names.resize(namecount);
- DVector<String>::Read r =snames.read();
- for(int i=0;i<names.size();i++)
- names[i]=r[i];
- }
-
- Array svariants = d["variants"];
-
- if (svariants.size()) {
- int varcount=svariants.size();
- variants.resize(varcount);
- for(int i=0;i<varcount;i++) {
-
- variants[i]=svariants[i];
- }
-
- } else {
- variants.clear();
- }
-
- nodes.resize(d["node_count"]);
- int nc=nodes.size();
- if (nc) {
- DVector<int> snodes = d["nodes"];
- DVector<int>::Read r = snodes.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- NodeData &nd = nodes[i];
- nd.parent=r[idx++];
- nd.type=r[idx++];
- nd.name=r[idx++];
- nd.properties.resize(r[idx++]);
- for(int j=0;j<nd.properties.size();j++) {
-
- nd.properties[j].name=r[idx++];
- nd.properties[j].value=r[idx++];
- }
- }
-
- }
-
- connections.resize(d["conn_count"]);
- int cc=connections.size();
-
- if (cc) {
-
- DVector<int> sconns = d["conns"];
- DVector<int>::Read r = sconns.read();
- int idx=0;
- for(int i=0;i<nc;i++) {
- ConnectionData &cd = connections[nc];
- cd.from=r[idx++];
- cd.to=r[idx++];
- cd.signal=r[idx++];
- cd.method=r[idx++];
- cd.binds.resize(r[idx++]);
- for(int j=0;j<cd.binds.size();j++) {
-
- cd.binds[j]=r[idx++];
- }
- }
-
- }
-
-
-
- path=d["path"];
-
-}
-
-Dictionary ScenePreloader::_get_bundled_scene() const {
-
- DVector<String> rnames;
- rnames.resize(names.size());
-
- if (names.size()) {
-
- DVector<String>::Write r=rnames.write();
-
- for(int i=0;i<names.size();i++)
- r[i]=names[i];
- }
-
- Dictionary d;
- d["names"]=rnames;
- d["variants"]=variants;
-
- Vector<int> rnodes;
- d["node_count"]=nodes.size();
-
- for(int i=0;i<nodes.size();i++) {
-
- const NodeData &nd=nodes[i];
- rnodes.push_back(nd.parent);
- rnodes.push_back(nd.type);
- rnodes.push_back(nd.name);
- rnodes.push_back(nd.properties.size());
- for(int j=0;j<nd.properties.size();j++) {
-
- rnodes.push_back(nd.properties[j].name);
- rnodes.push_back(nd.properties[j].value);
- }
- }
-
- d["nodes"]=rnodes;
-
- Vector<int> rconns;
- d["conn_count"]=connections.size();
-
- for(int i=0;i<connections.size();i++) {
-
- const ConnectionData &cd=connections[i];
- rconns.push_back(cd.from);
- rconns.push_back(cd.to);
- rconns.push_back(cd.signal);
- rconns.push_back(cd.method);
- rconns.push_back(cd.binds.size());
- for(int j=0;j<cd.binds.size();i++)
- rconns.push_back(cd.binds[j]);
-
- }
-
- d["conns"]=rconns;
-
- d["path"]=path;
-
- return d;
-
-
-}
-
-void ScenePreloader::_bind_methods() {
-
- ObjectTypeDB::bind_method(_MD("load_scene","path"),&ScenePreloader::load_scene);
- ObjectTypeDB::bind_method(_MD("get_scene_path"),&ScenePreloader::get_scene_path);
- ObjectTypeDB::bind_method(_MD("instance:Node"),&ScenePreloader::instance);
- ObjectTypeDB::bind_method(_MD("can_instance"),&ScenePreloader::can_instance);
- ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&ScenePreloader::_set_bundled_scene);
- ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&ScenePreloader::_get_bundled_scene);
-
- ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene"));
-#if 0
- List<String> extensions;
- SceneLoader::get_recognized_extensions(&extensions);
- String exthint;
- for (List<String>::Element*E=extensions.front();E;E=E->next()) {
-
- if (exthint!="")
- exthint+=",";
- exthint+="*."+E->get();
- }
-
- exthint+="; Scenes";
-
- ADD_PROPERTY( PropertyInfo(Variant::STRING,"scene",PROPERTY_HINT_FILE,exthint),_SCS("load_scene"),_SCS("get_scene_path"));
-#endif
-}
-
-ScenePreloader::ScenePreloader() {
-
-
-}
+#include "scene_preloader.h" +#include "globals.h" + +bool ScenePreloader::can_instance() const { + + return nodes.size()>0; +} + +Node *ScenePreloader::instance() const { + + int nc = nodes.size(); + ERR_FAIL_COND_V(nc==0,NULL); + + const StringName*snames=NULL; + int sname_count=names.size(); + if (sname_count) + snames=&names[0]; + + const Variant*props=NULL; + int prop_count=variants.size(); + if (prop_count) + props=&variants[0]; + + Vector<Variant> properties; + + const NodeData *nd = &nodes[0]; + + Node **ret_nodes=(Node**)alloca( sizeof(Node*)*nc ); + + 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; + } + + Object * obj = ObjectTypeDB::instance(snames[ n.type ]); + ERR_FAIL_COND_V(!obj,NULL); + Node *node = obj->cast_to<Node>(); + ERR_FAIL_COND_V(!node,NULL); + + int nprop_count=n.properties.size(); + if (nprop_count) { + + const NodeData::Property* nprops=&n.properties[0]; + + for(int j=0;j<nprop_count;j++) { + + bool valid; + node->set(snames[ nprops[j].name ],props[ nprops[j].value ],&valid); + } + + + } + + node->set_name( 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(node); + } + } + + + //do connections + + int cc = connections.size(); + const ConnectionData *cdata = connections.ptr(); + + 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 ); + + Vector<Variant> binds; + if (c.binds.size()) { + binds.resize(c.binds.size()); + for(int j=0;j<c.binds.size();j++) + 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 ); + } + + return ret_nodes[0]; + +} + + +static int _nm_get_string(const String& p_string, Map<StringName,int> &name_map) { + + if (name_map.has(p_string)) + return name_map[p_string]; + + int idx = name_map.size(); + name_map[p_string]=idx; + return idx; +} + +static int _vm_get_variant(const Variant& p_variant, HashMap<Variant,int,VariantHasher> &variant_map) { + + if (variant_map.has(p_variant)) + return variant_map[p_variant]; + + int idx = variant_map.size(); + variant_map[p_variant]=idx; + return idx; +} + +void ScenePreloader::_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) { + + if (p_node!=p_owner && !p_node->get_owner()) + return; + + 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; + + List<PropertyInfo> plist; + p_node->get_property_list(&plist); + for (List<PropertyInfo>::Element *E=plist.front();E;E=E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + + NodeData::Property prop; + prop.name=_nm_get_string(E->get().name,name_map); + prop.value=_vm_get_variant( p_node->get( E->get().name ), variant_map); + nd.properties.push_back(prop); + } + + int idx = nodes.size(); + node_map[p_node]=idx; + nodes.push_back(nd); + + for(int i=0;i<p_node->get_child_count();i++) { + + Node *c=p_node->get_child(i); + _parse_node(p_owner,c,idx,name_map,variant_map,node_map); + } + + + +} + +void ScenePreloader::_parse_connections(Node *p_node, Map<StringName,int> &name_map,HashMap<Variant,int,VariantHasher> &variant_map,Map<Node*,int> &node_map,bool p_instance) { + + + List<MethodInfo> signals; + p_node->get_signal_list(&signals); + + 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)) + continue; + Node *n=c.target->cast_to<Node>(); + if (!n) + continue; + + if (!node_map.has(n)) + continue; + + ConnectionData cd; + cd.from=node_map[p_node]; + cd.to=node_map[n]; + cd.method=_nm_get_string(c.method,name_map); + cd.signal=_nm_get_string(c.signal,name_map); + for(int i=0;i<c.binds.size();i++) { + + cd.binds.push_back( _vm_get_variant(c.binds[i],variant_map)); + } + connections.push_back(cd); + } + } + +} + + +Error ScenePreloader::load_scene(const String& p_path) { + + return ERR_CANT_OPEN; +#if 0 + if (path==p_path) + return OK; + + String p=Globals::get_singleton()->localize_path(p_path); + clear(); + + Node *scene = SceneLoader::load(p); + + ERR_FAIL_COND_V(!scene,ERR_CANT_OPEN); + + path=p; + + Map<StringName,int> name_map; + HashMap<Variant,int,VariantHasher> variant_map; + Map<Node*,int> node_map; + + _parse_node(scene,scene,-1,name_map,variant_map,node_map); + + + names.resize(name_map.size()); + + for(Map<StringName,int>::Element *E=name_map.front();E;E=E->next()) { + + names[E->get()]=E->key(); + } + + variants.resize(variant_map.size()); + const Variant *K=NULL; + while((K=variant_map.next(K))) { + + int idx = variant_map[*K]; + variants[idx]=*K; + } + + + memdelete(scene); // <- me falto esto :( + return OK; +#endif +} + +String ScenePreloader::get_scene_path() const { + + return path; +} + +void ScenePreloader::clear() { + + names.clear(); + variants.clear(); + nodes.clear(); + connections.clear(); + +} + +void ScenePreloader::_set_bundled_scene(const Dictionary& d) { + + + ERR_FAIL_COND( !d.has("names")); + ERR_FAIL_COND( !d.has("variants")); + ERR_FAIL_COND( !d.has("node_count")); + ERR_FAIL_COND( !d.has("nodes")); + ERR_FAIL_COND( !d.has("conn_count")); + ERR_FAIL_COND( !d.has("conns")); + ERR_FAIL_COND( !d.has("path")); + + DVector<String> snames = d["names"]; + if (snames.size()) { + + int namecount = snames.size(); + names.resize(namecount); + DVector<String>::Read r =snames.read(); + for(int i=0;i<names.size();i++) + names[i]=r[i]; + } + + Array svariants = d["variants"]; + + if (svariants.size()) { + int varcount=svariants.size(); + variants.resize(varcount); + for(int i=0;i<varcount;i++) { + + variants[i]=svariants[i]; + } + + } else { + variants.clear(); + } + + nodes.resize(d["node_count"]); + int nc=nodes.size(); + if (nc) { + DVector<int> snodes = d["nodes"]; + DVector<int>::Read r = snodes.read(); + int idx=0; + for(int i=0;i<nc;i++) { + NodeData &nd = nodes[i]; + nd.parent=r[idx++]; + nd.type=r[idx++]; + nd.name=r[idx++]; + nd.properties.resize(r[idx++]); + for(int j=0;j<nd.properties.size();j++) { + + nd.properties[j].name=r[idx++]; + nd.properties[j].value=r[idx++]; + } + } + + } + + connections.resize(d["conn_count"]); + int cc=connections.size(); + + if (cc) { + + DVector<int> sconns = d["conns"]; + DVector<int>::Read r = sconns.read(); + int idx=0; + for(int i=0;i<nc;i++) { + ConnectionData &cd = connections[nc]; + cd.from=r[idx++]; + cd.to=r[idx++]; + cd.signal=r[idx++]; + cd.method=r[idx++]; + cd.binds.resize(r[idx++]); + for(int j=0;j<cd.binds.size();j++) { + + cd.binds[j]=r[idx++]; + } + } + + } + + + + path=d["path"]; + +} + +Dictionary ScenePreloader::_get_bundled_scene() const { + + DVector<String> rnames; + rnames.resize(names.size()); + + if (names.size()) { + + DVector<String>::Write r=rnames.write(); + + for(int i=0;i<names.size();i++) + r[i]=names[i]; + } + + Dictionary d; + d["names"]=rnames; + d["variants"]=variants; + + Vector<int> rnodes; + d["node_count"]=nodes.size(); + + for(int i=0;i<nodes.size();i++) { + + const NodeData &nd=nodes[i]; + rnodes.push_back(nd.parent); + rnodes.push_back(nd.type); + rnodes.push_back(nd.name); + rnodes.push_back(nd.properties.size()); + for(int j=0;j<nd.properties.size();j++) { + + rnodes.push_back(nd.properties[j].name); + rnodes.push_back(nd.properties[j].value); + } + } + + d["nodes"]=rnodes; + + Vector<int> rconns; + d["conn_count"]=connections.size(); + + for(int i=0;i<connections.size();i++) { + + const ConnectionData &cd=connections[i]; + rconns.push_back(cd.from); + rconns.push_back(cd.to); + rconns.push_back(cd.signal); + rconns.push_back(cd.method); + rconns.push_back(cd.binds.size()); + for(int j=0;j<cd.binds.size();i++) + rconns.push_back(cd.binds[j]); + + } + + d["conns"]=rconns; + + d["path"]=path; + + return d; + + +} + +void ScenePreloader::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("load_scene","path"),&ScenePreloader::load_scene); + ObjectTypeDB::bind_method(_MD("get_scene_path"),&ScenePreloader::get_scene_path); + ObjectTypeDB::bind_method(_MD("instance:Node"),&ScenePreloader::instance); + ObjectTypeDB::bind_method(_MD("can_instance"),&ScenePreloader::can_instance); + ObjectTypeDB::bind_method(_MD("_set_bundled_scene"),&ScenePreloader::_set_bundled_scene); + ObjectTypeDB::bind_method(_MD("_get_bundled_scene"),&ScenePreloader::_get_bundled_scene); + + ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled_scene"),_SCS("_get_bundled_scene")); +#if 0 + List<String> extensions; + SceneLoader::get_recognized_extensions(&extensions); + String exthint; + for (List<String>::Element*E=extensions.front();E;E=E->next()) { + + if (exthint!="") + exthint+=","; + exthint+="*."+E->get(); + } + + exthint+="; Scenes"; + + ADD_PROPERTY( PropertyInfo(Variant::STRING,"scene",PROPERTY_HINT_FILE,exthint),_SCS("load_scene"),_SCS("get_scene_path")); +#endif +} + +ScenePreloader::ScenePreloader() { + + +} diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 6d65da3782..42251124bd 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -33,12 +33,6 @@ #include "scene/scene_string_names.h" -void Shader::set_mode(Mode p_mode) { - - ERR_FAIL_INDEX(p_mode,2); - VisualServer::get_singleton()->shader_set_mode(shader,VisualServer::ShaderMode(p_mode)); - emit_signal(SceneStringNames::get_singleton()->changed); -} Shader::Mode Shader::get_mode() const { @@ -90,7 +84,7 @@ void Shader::get_param_list(List<PropertyInfo> *p_params) const { for(List<PropertyInfo>::Element *E=local.front();E;E=E->next()) { PropertyInfo pi=E->get(); - pi.name="param/"+pi.name; + pi.name="shader_param/"+pi.name; params_cache[pi.name]=E->get().name; if (p_params) { @@ -120,6 +114,13 @@ Dictionary Shader::_get_code() { c["vertex_ofs"]=0; c["light"]=ls; c["light_ofs"]=0; + Array arr; + for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) { + arr.push_back(E->key()); + arr.push_back(E->get()); + } + if (arr.size()) + c["default_tex"]=arr; return c; } @@ -132,11 +133,46 @@ void Shader::_set_code(const Dictionary& p_string) { light=p_string["light"]; set_code(p_string["vertex"],p_string["fragment"],light); + if (p_string.has("default_tex")) { + Array arr=p_string["default_tex"]; + if ((arr.size()&1)==0) { + for(int i=0;i<arr.size();i+=2) + set_default_texture_param(arr[i],arr[i+1]); + } + } } +void Shader::set_default_texture_param(const StringName& p_param,const Ref<Texture>& p_texture) { + + if (p_texture.is_valid()) { + default_textures[p_param]=p_texture; + VS::get_singleton()->shader_set_default_texture_param(shader,p_param,p_texture->get_rid()); + } else { + default_textures.erase(p_param); + VS::get_singleton()->shader_set_default_texture_param(shader,p_param,RID()); + } +} + +Ref<Texture> Shader::get_default_texture_param(const StringName& p_param) const{ + + if (default_textures.has(p_param)) + return default_textures[p_param]; + else + return Ref<Texture>(); +} + +void Shader::get_default_texture_param_list(List<StringName>* r_textures) const{ + + for(const Map<StringName,Ref<Texture> >::Element *E=default_textures.front();E;E=E->next()) { + + r_textures->push_back(E->key()); + } + +} + + void Shader::_bind_methods() { - ObjectTypeDB::bind_method(_MD("set_mode","mode"),&Shader::set_mode); ObjectTypeDB::bind_method(_MD("get_mode"),&Shader::get_mode); ObjectTypeDB::bind_method(_MD("set_code","vcode","fcode","lcode","fofs","lofs"),&Shader::set_code,DEFVAL(0),DEFVAL(0)); @@ -144,6 +180,9 @@ void Shader::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_fragment_code"),&Shader::get_fragment_code); ObjectTypeDB::bind_method(_MD("get_light_code"),&Shader::get_light_code); + ObjectTypeDB::bind_method(_MD("set_default_texture_param","param","texture:Texture"),&Shader::set_default_texture_param); + ObjectTypeDB::bind_method(_MD("get_default_texture_param:Texture","param"),&Shader::get_default_texture_param); + ObjectTypeDB::bind_method(_MD("has_param","name"),&Shader::has_param); ObjectTypeDB::bind_method(_MD("_set_code","code"),&Shader::_set_code); @@ -160,9 +199,9 @@ void Shader::_bind_methods() { } -Shader::Shader() { +Shader::Shader(Mode p_mode) { - shader = VisualServer::get_singleton()->shader_create(); + shader = VisualServer::get_singleton()->shader_create(VS::ShaderMode(p_mode)); params_cache_dirty=true; } @@ -194,7 +233,7 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin String base_path = p_path.get_base_dir(); - Ref<Shader> shader( memnew( Shader ) ); + Ref<Shader> shader;//( memnew( Shader ) ); int line=0; diff --git a/scene/resources/shader.h b/scene/resources/shader.h index fff6f1d28a..4a380d455b 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -31,7 +31,7 @@ #include "resource.h" #include "io/resource_loader.h" - +#include "scene/resources/texture.h" class Shader : public Resource { OBJ_TYPE(Shader,Resource); @@ -48,6 +48,9 @@ class Shader : public Resource { // convertion fast and save memory. mutable bool params_cache_dirty; mutable Map<StringName,StringName> params_cache; //map a shader param to a material param.. + Map<StringName,Ref<Texture> > default_textures; + + protected: @@ -58,10 +61,11 @@ public: MODE_MATERIAL, MODE_CANVAS_ITEM, - MODE_POST_PROCESS + MODE_POST_PROCESS, + MODE_MAX }; - void set_mode(Mode p_mode); + //void set_mode(Mode p_mode); Mode get_mode() const; void set_code( const String& p_vertex, const String& p_fragment, const String& p_light,int p_fragment_ofs=0,int p_light_ofs=0); @@ -72,15 +76,47 @@ public: void get_param_list(List<PropertyInfo> *p_params) const; bool has_param(const StringName& p_param) const; + void set_default_texture_param(const StringName& p_param, const Ref<Texture> &p_texture); + Ref<Texture> get_default_texture_param(const StringName& p_param) const; + void get_default_texture_param_list(List<StringName>* r_textures) const; + + _FORCE_INLINE_ StringName remap_param(const StringName& p_param) const { + if (params_cache_dirty) + get_param_list(NULL); + + const Map<StringName,StringName>::Element *E=params_cache.find(p_param); + if (E) + return E->get(); + return StringName(); + } + virtual RID get_rid() const; - Shader(); + Shader(Mode p_mode); ~Shader(); }; VARIANT_ENUM_CAST( Shader::Mode ); +class MaterialShader : public Shader { + + OBJ_TYPE(MaterialShader,Shader); + +public: + + MaterialShader() : Shader(MODE_MATERIAL) {}; +}; + +class CanvasItemShader : public Shader { + + OBJ_TYPE(CanvasItemShader,Shader); + +public: + + CanvasItemShader() : Shader(MODE_CANVAS_ITEM) {}; +}; + class ResourceFormatLoaderShader : public ResourceFormatLoader { diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp index df5fee81a8..9703799a48 100644 --- a/scene/resources/shader_graph.cpp +++ b/scene/resources/shader_graph.cpp @@ -27,129 +27,351 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "shader_graph.h" +#include "scene/scene_string_names.h" +Array ShaderGraph::_get_node_list(ShaderType p_type) const { + List<int> nodes; + get_node_list(p_type,&nodes); + Array arr(true); + for (List<int>::Element *E=nodes.front();E;E=E->next()) + arr.push_back(E->get()); + return arr; +} +Array ShaderGraph::_get_connections(ShaderType p_type) const { + + List<Connection> connections; + get_node_connections(p_type,&connections); + Array arr(true); + for (List<Connection>::Element *E=connections.front();E;E=E->next()) { + + Dictionary d(true); + d["src_id"]=E->get().src_id; + d["src_slot"]=E->get().src_slot; + d["dst_id"]=E->get().dst_id; + d["dst_slot"]=E->get().dst_slot; + arr.push_back(d); -# if 0 -void ShaderGraph::_set(const String& p_name, const Variant& p_value) { + } + return arr; +} - if (p_name.begins_with("nodes/")) { - int idx=p_name.get_slice("/",1).to_int(); - Dictionary data=p_value; +void ShaderGraph::_set_data(const Dictionary &p_data) { - ERR_FAIL_COND(!data.has("type")); - String type=data["type"]; + Dictionary d=p_data; + ERR_FAIL_COND(!d.has("shaders")); + Array sh=d["shaders"]; + ERR_FAIL_COND(sh.size()!=3); - VS::NodeType node_type=VS::NODE_TYPE_MAX; - for(int i=0;i<NODE_TYPE_MAX;i++) { + for(int t=0;t<3;t++) { + Array data=sh[t]; + ERR_FAIL_COND((data.size()%6)!=0); + shader[t].node_map.clear(); + for(int i=0;i<data.size();i+=6) { - if (type==VisualServer::shader_node_get_type_info((VS::NodeType)i).name) - node_type=(VS::NodeType)i; - } + Node n; + n.id=data[i+0]; + n.type=NodeType(int(data[i+1])); + n.pos=data[i+2]; + n.param1=data[i+3]; + n.param2=data[i+4]; - ERR_FAIL_COND(node_type==VS::NODE_TYPE_MAX); + Array conns=data[i+5]; + ERR_FAIL_COND((conns.size()%3)!=0); - node_add( (NodeType)node_type, idx ); - if (data.has("param")) - node_set_param(idx,data["param"]); - if (data.has("pos")) - node_set_pos(idx,data["pos"]); - } + for(int j=0;j<conns.size();j+=3) { - if (p_name.begins_with("conns/")) { - Dictionary data=p_value; - ERR_FAIL_COND( !data.has("src_id") ); - ERR_FAIL_COND( !data.has("src_slot") ); - ERR_FAIL_COND( !data.has("dst_id") ); - ERR_FAIL_COND( !data.has("dst_slot") ); + SourceSlot ss; + int ls=conns[j+0]; + ss.id=conns[j+1]; + ss.slot=conns[j+2]; + n.connections[ls]=ss; + } + shader[t].node_map[n.id]=n; - connect(data["src_id"],data["src_slot"],data["dst_id"],data["dst_slot"]); + } } - return false; + _update_shader(); + } -Variant ShaderGraph::_get(const String& p_name) const { - if (p_name.begins_with("nodes/")) { - int idx=p_name.get_slice("/",1).to_int(); - Dictionary data; - data["type"]=VisualServer::shader_node_get_type_info((VS::NodeType)node_get_type(idx)).name; - data["pos"]=node_get_pos(idx); - data["param"]=node_get_param(idx); - return data; - } - if (p_name.begins_with("conns/")) { - int idx=p_name.get_slice("/",1).to_int(); - Dictionary data; - - List<Connection> connections; - get_connections(&connections); - ERR_FAIL_INDEX_V( idx,connections.size(), Variant() ); - Connection c = connections[idx]; - - data["src_id"]=c.src_id; - data["src_slot"]=c.src_slot; - data["dst_id"]=c.dst_id; - data["dst_slot"]=c.dst_slot; - return data; +Dictionary ShaderGraph::_get_data() const { + + Array sh; + for(int i=0;i<3;i++) { + Array data; + int ec = shader[i].node_map.size(); + data.resize(ec*6); + int idx=0; + for (Map<int,Node>::Element*E=shader[i].node_map.front();E;E=E->next()) { + + data[idx+0]=E->key(); + data[idx+1]=E->get().type; + data[idx+2]=E->get().pos; + data[idx+3]=E->get().param1; + data[idx+4]=E->get().param2; + + Array conns; + conns.resize(E->get().connections.size()*3); + int idx2=0; + for(Map<int,SourceSlot>::Element*F=E->get().connections.front();F;F=F->next()) { + + conns[idx2+0]=F->key(); + conns[idx2+1]=F->get().id; + conns[idx2+2]=F->get().slot; + idx2+=3; + } + data[idx+5]=conns; + idx+=6; + } + sh.push_back(data); } - return Variant(); + Dictionary data; + data["shaders"]=sh; + return data; } -void ShaderGraph::_get_property_list( List<PropertyInfo> *p_list) const { - List<int> nodes; - get_node_list(&nodes); - for(List<int>::Element *E=nodes.front();E;E=E->next()) { - int idx=E->get(); - p_list->push_back(PropertyInfo( Variant::DICTIONARY , "nodes/"+itos(idx),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) ); - } - - List<Connection> connections; - get_connections(&connections); - int idx=0; - for(List<Connection>::Element *E=connections.front();E;E=E->next()) { - p_list->push_back(PropertyInfo( Variant::DICTIONARY , "conns/"+itos(idx++),PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NETWORK|PROPERTY_USAGE_STORAGE ) ); - } +ShaderGraph::GraphError ShaderGraph::get_graph_error(ShaderType p_type) const { + ERR_FAIL_INDEX_V(p_type,3,GRAPH_OK); + return shader[p_type].error; } -#endif -#if 0 -Array ShaderGraph::_get_connections_helper() const { +void ShaderGraph::_bind_methods() { - Array connections_ret; - List<Connection> connections; - get_connections(&connections); - connections_ret.resize(connections.size()); - - int idx=0; - for(List<Connection>::Element *E=connections.front();E;E=E->next()) { - - Connection c = E->get(); - Dictionary data; - data["src_id"]=c.src_id; - data["src_slot"]=c.src_slot; - data["dst_id"]=c.dst_id; - data["dst_slot"]=c.dst_slot; - connections_ret.set(idx++,data); - } + ObjectTypeDB::bind_method(_MD("_update_shader"),&ShaderGraph::_update_shader); - return connections_ret; -} + ObjectTypeDB::bind_method(_MD("node_add","shader_type","node_type","id"),&ShaderGraph::node_add); + ObjectTypeDB::bind_method(_MD("node_remove","shader_type","id"),&ShaderGraph::node_remove); + ObjectTypeDB::bind_method(_MD("node_set_pos","shader_type","id","pos"),&ShaderGraph::node_set_pos); + ObjectTypeDB::bind_method(_MD("node_get_pos","shader_type","id"),&ShaderGraph::node_get_pos); -void ShaderGraph::_bind_methods() { + ObjectTypeDB::bind_method(_MD("node_get_type","shader_type","id"),&ShaderGraph::node_get_type); + + ObjectTypeDB::bind_method(_MD("get_node_list","shader_type"),&ShaderGraph::_get_node_list); + + ObjectTypeDB::bind_method(_MD("scalar_const_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_const_node_set_value); + ObjectTypeDB::bind_method(_MD("scalar_const_node_get_value","shader_type","id"),&ShaderGraph::scalar_const_node_set_value); + + ObjectTypeDB::bind_method(_MD("vec_const_node_set_value","shader_type","id","value"),&ShaderGraph::vec_const_node_set_value); + ObjectTypeDB::bind_method(_MD("vec_const_node_get_value","shader_type","id"),&ShaderGraph::vec_const_node_set_value); + + ObjectTypeDB::bind_method(_MD("rgb_const_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_const_node_set_value); + ObjectTypeDB::bind_method(_MD("rgb_const_node_get_value","shader_type","id"),&ShaderGraph::rgb_const_node_set_value); + + ObjectTypeDB::bind_method(_MD("xform_const_node_set_value","shader_type","id","value"),&ShaderGraph::xform_const_node_set_value); + ObjectTypeDB::bind_method(_MD("xform_const_node_get_value","shader_type","id"),&ShaderGraph::xform_const_node_set_value); + + +// void get_node_list(ShaderType p_which,List<int> *p_node_list) const; + + ObjectTypeDB::bind_method(_MD("texture_node_set_filter_size","shader_type","id","filter_size"),&ShaderGraph::texture_node_set_filter_size); + ObjectTypeDB::bind_method(_MD("texture_node_get_filter_size","shader_type","id"),&ShaderGraph::texture_node_set_filter_size); + + ObjectTypeDB::bind_method(_MD("texture_node_set_filter_strength","shader_type","id","filter_strength"),&ShaderGraph::texture_node_set_filter_strength); + ObjectTypeDB::bind_method(_MD("texture_node_get_filter_strength","shader_type","id"),&ShaderGraph::texture_node_set_filter_strength); + + ObjectTypeDB::bind_method(_MD("scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::scalar_op_node_set_op); + ObjectTypeDB::bind_method(_MD("scalar_op_node_get_op","shader_type","id"),&ShaderGraph::scalar_op_node_get_op); + + ObjectTypeDB::bind_method(_MD("vec_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_op_node_set_op); + ObjectTypeDB::bind_method(_MD("vec_op_node_get_op","shader_type","id"),&ShaderGraph::vec_op_node_get_op); + + ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_set_op","shader_type","id","op"),&ShaderGraph::vec_scalar_op_node_set_op); + ObjectTypeDB::bind_method(_MD("vec_scalar_op_node_get_op","shader_type","id"),&ShaderGraph::vec_scalar_op_node_get_op); + + ObjectTypeDB::bind_method(_MD("rgb_op_node_set_op","shader_type","id","op"),&ShaderGraph::rgb_op_node_set_op); + ObjectTypeDB::bind_method(_MD("rgb_op_node_get_op","shader_type","id"),&ShaderGraph::rgb_op_node_get_op); + + ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_set_no_translation","shader_type","id","disable"),&ShaderGraph::xform_vec_mult_node_set_no_translation); + ObjectTypeDB::bind_method(_MD("xform_vec_mult_node_get_no_translation","shader_type","id"),&ShaderGraph::xform_vec_mult_node_get_no_translation); + + ObjectTypeDB::bind_method(_MD("scalar_func_node_set_function","shader_type","id","func"),&ShaderGraph::scalar_func_node_set_function); + ObjectTypeDB::bind_method(_MD("scalar_func_node_get_function","shader_type","id"),&ShaderGraph::scalar_func_node_get_function); + + ObjectTypeDB::bind_method(_MD("vec_func_node_set_function","shader_type","id","func"),&ShaderGraph::vec_func_node_set_function); + ObjectTypeDB::bind_method(_MD("vec_func_node_get_function","shader_type","id"),&ShaderGraph::vec_func_node_get_function); + + ObjectTypeDB::bind_method(_MD("input_node_set_name","shader_type","id","name"),&ShaderGraph::input_node_set_name); + ObjectTypeDB::bind_method(_MD("input_node_get_name","shader_type","id"),&ShaderGraph::input_node_get_name); + + ObjectTypeDB::bind_method(_MD("scalar_input_node_set_value","shader_type","id","value"),&ShaderGraph::scalar_input_node_set_value); + ObjectTypeDB::bind_method(_MD("scalar_input_node_get_value","shader_type","id"),&ShaderGraph::scalar_input_node_get_value); + + ObjectTypeDB::bind_method(_MD("vec_input_node_set_value","shader_type","id","value"),&ShaderGraph::vec_input_node_set_value); + ObjectTypeDB::bind_method(_MD("vec_input_node_get_value","shader_type","id"),&ShaderGraph::vec_input_node_get_value); + + ObjectTypeDB::bind_method(_MD("rgb_input_node_set_value","shader_type","id","value"),&ShaderGraph::rgb_input_node_set_value); + ObjectTypeDB::bind_method(_MD("rgb_input_node_get_value","shader_type","id"),&ShaderGraph::rgb_input_node_get_value); + + ObjectTypeDB::bind_method(_MD("xform_input_node_set_value","shader_type","id","value"),&ShaderGraph::xform_input_node_set_value); + ObjectTypeDB::bind_method(_MD("xform_input_node_get_value","shader_type","id"),&ShaderGraph::xform_input_node_get_value); + + ObjectTypeDB::bind_method(_MD("texture_input_node_set_value","shader_type","id","value:Texture"),&ShaderGraph::texture_input_node_set_value); + ObjectTypeDB::bind_method(_MD("texture_input_node_get_value:Texture","shader_type","id"),&ShaderGraph::texture_input_node_get_value); + + ObjectTypeDB::bind_method(_MD("cubemap_input_node_set_value","shader_type","id","value:CubeMap"),&ShaderGraph::cubemap_input_node_set_value); + ObjectTypeDB::bind_method(_MD("cubemap_input_node_get_value:CubeMap","shader_type","id"),&ShaderGraph::cubemap_input_node_get_value); + + ObjectTypeDB::bind_method(_MD("comment_node_set_text","shader_type","id","text"),&ShaderGraph::comment_node_set_text); + ObjectTypeDB::bind_method(_MD("comment_node_get_text","shader_type","id"),&ShaderGraph::comment_node_get_text); + + ObjectTypeDB::bind_method(_MD("connect_node:Error","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::connect_node); + ObjectTypeDB::bind_method(_MD("is_node_connected","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::is_node_connected); + ObjectTypeDB::bind_method(_MD("disconnect_node","shader_type","src_id","src_slot","dst_id","dst_slot"),&ShaderGraph::disconnect_node); + ObjectTypeDB::bind_method(_MD("get_node_connections","shader_type"),&ShaderGraph::_get_connections); + + ObjectTypeDB::bind_method(_MD("clear","shader_type"),&ShaderGraph::clear); + + ObjectTypeDB::bind_method(_MD("node_set_state","shader_type","id","state"),&ShaderGraph::node_set_state); + ObjectTypeDB::bind_method(_MD("node_get_state:var","shader_type","id"),&ShaderGraph::node_get_state); + + ObjectTypeDB::bind_method(_MD("_set_data"),&ShaderGraph::_set_data); + ObjectTypeDB::bind_method(_MD("_get_data"),&ShaderGraph::_get_data); + + ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), _SCS("_set_data"),_SCS("_get_data")); + + //void get_connections(ShaderType p_which,List<Connection> *p_connections) const; + + + BIND_CONSTANT( NODE_INPUT ); // all inputs (shader type dependent) + BIND_CONSTANT( NODE_SCALAR_CONST ); //scalar constant + BIND_CONSTANT( NODE_VEC_CONST ); //vec3 constant + BIND_CONSTANT( NODE_RGB_CONST ); //rgb constant (shows a color picker instead) + BIND_CONSTANT( NODE_XFORM_CONST ); // 4x4 matrix constant + BIND_CONSTANT( NODE_TIME ); // time in seconds + BIND_CONSTANT( NODE_SCREEN_TEX ); // screen texture sampler (takes UV) (only usable in fragment shader) + BIND_CONSTANT( NODE_SCALAR_OP ); // scalar vs scalar op (mul ); add ); div ); etc) + BIND_CONSTANT( NODE_VEC_OP ); // vec3 vs vec3 op (mul );ad );div );crossprod );etc) + BIND_CONSTANT( NODE_VEC_SCALAR_OP ); // vec3 vs scalar op (mul ); add ); div ); etc) + BIND_CONSTANT( NODE_RGB_OP ); // vec3 vs vec3 rgb op (with scalar amount) ); like brighten ); darken ); burn ); dodge ); multiply ); etc. + BIND_CONSTANT( NODE_XFORM_MULT ); // mat4 x mat4 + BIND_CONSTANT( NODE_XFORM_VEC_MULT ); // mat4 x vec3 mult (with no-translation option) + BIND_CONSTANT( NODE_XFORM_VEC_INV_MULT ); // mat4 x vec3 inverse mult (with no-translation option) + BIND_CONSTANT( NODE_SCALAR_FUNC ); // scalar function (sin ); cos ); etc) + BIND_CONSTANT( NODE_VEC_FUNC ); // vector function (normalize ); negate ); reciprocal ); rgb2hsv ); hsv2rgb ); etc ); etc) + BIND_CONSTANT( NODE_VEC_LEN ); // vec3 length + BIND_CONSTANT( NODE_DOT_PROD ); // vec3 . vec3 (dot product -> scalar output) + BIND_CONSTANT( NODE_VEC_TO_SCALAR ); // 1 vec3 input ); 3 scalar outputs + BIND_CONSTANT( NODE_SCALAR_TO_VEC ); // 3 scalar input ); 1 vec3 output + BIND_CONSTANT( NODE_VEC_TO_XFORM ); // 3 vec input ); 1 xform output + BIND_CONSTANT( NODE_XFORM_TO_VEC ); // 3 vec input ); 1 xform output + BIND_CONSTANT( NODE_SCALAR_INTERP ); // scalar interpolation (with optional curve) + BIND_CONSTANT( NODE_VEC_INTERP ); // vec3 interpolation (with optional curve) + BIND_CONSTANT( NODE_SCALAR_INPUT ); // scalar uniform (assignable in material) + BIND_CONSTANT( NODE_VEC_INPUT ); // vec3 uniform (assignable in material) + BIND_CONSTANT( NODE_RGB_INPUT ); // color uniform (assignable in material) + BIND_CONSTANT( NODE_XFORM_INPUT ); // mat4 uniform (assignable in material) + BIND_CONSTANT( NODE_TEXTURE_INPUT ); // texture input (assignable in material) + BIND_CONSTANT( NODE_CUBEMAP_INPUT ); // cubemap input (assignable in material) + BIND_CONSTANT( NODE_OUTPUT ); // output (shader type dependent) + BIND_CONSTANT( NODE_COMMENT ); // comment + BIND_CONSTANT( NODE_TYPE_MAX ); + + BIND_CONSTANT( SLOT_TYPE_SCALAR ); + BIND_CONSTANT( SLOT_TYPE_VEC ); + BIND_CONSTANT( SLOT_TYPE_XFORM ); + BIND_CONSTANT( SLOT_TYPE_TEXTURE ); + BIND_CONSTANT( SLOT_MAX ); + + BIND_CONSTANT( SHADER_TYPE_VERTEX ); + BIND_CONSTANT( SHADER_TYPE_FRAGMENT ); + BIND_CONSTANT( SHADER_TYPE_LIGHT ); + BIND_CONSTANT( SHADER_TYPE_MAX ); + + + BIND_CONSTANT( SLOT_IN ); + BIND_CONSTANT( SLOT_OUT ); + + BIND_CONSTANT( GRAPH_OK ); + BIND_CONSTANT( GRAPH_ERROR_CYCLIC ); + BIND_CONSTANT( GRAPH_ERROR_MISSING_CONNECTIONS ); + + BIND_CONSTANT( SCALAR_OP_ADD ); + BIND_CONSTANT( SCALAR_OP_SUB ); + BIND_CONSTANT( SCALAR_OP_MUL ); + BIND_CONSTANT( SCALAR_OP_DIV ); + BIND_CONSTANT( SCALAR_OP_MOD ); + BIND_CONSTANT( SCALAR_OP_POW ); + BIND_CONSTANT( SCALAR_OP_MAX ); + BIND_CONSTANT( SCALAR_OP_MIN ); + BIND_CONSTANT( SCALAR_OP_ATAN2 ); + BIND_CONSTANT( SCALAR_MAX_OP ); + + BIND_CONSTANT( VEC_OP_ADD ); + BIND_CONSTANT( VEC_OP_SUB ); + BIND_CONSTANT( VEC_OP_MUL ); + BIND_CONSTANT( VEC_OP_DIV ); + BIND_CONSTANT( VEC_OP_MOD ); + BIND_CONSTANT( VEC_OP_POW ); + BIND_CONSTANT( VEC_OP_MAX ); + BIND_CONSTANT( VEC_OP_MIN ); + BIND_CONSTANT( VEC_OP_CROSS ); + BIND_CONSTANT( VEC_MAX_OP ); + + BIND_CONSTANT( VEC_SCALAR_OP_MUL ); + BIND_CONSTANT( VEC_SCALAR_OP_DIV ); + BIND_CONSTANT( VEC_SCALAR_OP_POW ); + BIND_CONSTANT( VEC_SCALAR_MAX_OP ); + + BIND_CONSTANT( RGB_OP_SCREEN ); + BIND_CONSTANT( RGB_OP_DIFFERENCE ); + BIND_CONSTANT( RGB_OP_DARKEN ); + BIND_CONSTANT( RGB_OP_LIGHTEN ); + BIND_CONSTANT( RGB_OP_OVERLAY ); + BIND_CONSTANT( RGB_OP_DODGE ); + BIND_CONSTANT( RGB_OP_BURN ); + BIND_CONSTANT( RGB_OP_SOFT_LIGHT ); + BIND_CONSTANT( RGB_OP_HARD_LIGHT ); + BIND_CONSTANT( RGB_MAX_OP ); + + BIND_CONSTANT( SCALAR_FUNC_SIN ); + BIND_CONSTANT( SCALAR_FUNC_COS ); + BIND_CONSTANT( SCALAR_FUNC_TAN ); + BIND_CONSTANT( SCALAR_FUNC_ASIN ); + BIND_CONSTANT( SCALAR_FUNC_ACOS ); + BIND_CONSTANT( SCALAR_FUNC_ATAN ); + BIND_CONSTANT( SCALAR_FUNC_SINH ); + BIND_CONSTANT( SCALAR_FUNC_COSH ); + BIND_CONSTANT( SCALAR_FUNC_TANH ); + BIND_CONSTANT( SCALAR_FUNC_LOG ); + BIND_CONSTANT( SCALAR_FUNC_EXP ); + BIND_CONSTANT( SCALAR_FUNC_SQRT ); + BIND_CONSTANT( SCALAR_FUNC_ABS ); + BIND_CONSTANT( SCALAR_FUNC_SIGN ); + BIND_CONSTANT( SCALAR_FUNC_FLOOR ); + BIND_CONSTANT( SCALAR_FUNC_ROUND ); + BIND_CONSTANT( SCALAR_FUNC_CEIL ); + BIND_CONSTANT( SCALAR_FUNC_FRAC ); + BIND_CONSTANT( SCALAR_FUNC_SATURATE ); + BIND_CONSTANT( SCALAR_FUNC_NEGATE ); + BIND_CONSTANT( SCALAR_MAX_FUNC ); + + BIND_CONSTANT( VEC_FUNC_NORMALIZE ); + BIND_CONSTANT( VEC_FUNC_SATURATE ); + BIND_CONSTANT( VEC_FUNC_NEGATE ); + BIND_CONSTANT( VEC_FUNC_RECIPROCAL ); + BIND_CONSTANT( VEC_FUNC_RGB2HSV ); + BIND_CONSTANT( VEC_FUNC_HSV2RGB ); + BIND_CONSTANT( VEC_MAX_FUNC ); + + ADD_SIGNAL(MethodInfo("updated")); + + +#if 0 ObjectTypeDB::bind_method(_MD("node_add"),&ShaderGraph::node_add ); ObjectTypeDB::bind_method(_MD("node_remove"),&ShaderGraph::node_remove ); ObjectTypeDB::bind_method(_MD("node_set_param"),&ShaderGraph::node_set_param ); ObjectTypeDB::bind_method(_MD("node_set_pos"),&ShaderGraph::node_set_pos ); ObjectTypeDB::bind_method(_MD("node_get_pos"),&ShaderGraph::node_get_pos ); - ObjectTypeDB::bind_method(_MD("node_get_param"),&ShaderGraph::node_get_type); - ObjectTypeDB::bind_method(_MD("node_get_type"),&ShaderGraph::node_get_param); + ObjectTypeDB::bind_method(_MD("node_get_param"),&ShaderGraph::node_get_param); + ObjectTypeDB::bind_method(_MD("node_get_type"),&ShaderGraph::node_get_type); ObjectTypeDB::bind_method(_MD("connect"),&ShaderGraph::connect ); ObjectTypeDB::bind_method(_MD("disconnect"),&ShaderGraph::disconnect ); @@ -212,73 +434,158 @@ void ShaderGraph::_bind_methods() { BIND_CONSTANT( NODE_TEXTURE_2D_PARAMETER ); BIND_CONSTANT( NODE_TEXTURE_CUBE_PARAMETER ); BIND_CONSTANT( NODE_TYPE_MAX ); +#endif } -void ShaderGraph::node_add(NodeType p_type,int p_id) { + +String ShaderGraph::_find_unique_name(const String& p_base) { + - ERR_FAIL_COND( node_map.has(p_id ) ); - ERR_FAIL_INDEX( p_type, NODE_TYPE_MAX ); + int idx=1; + while(true) { + String tocmp=p_base; + if (idx>1) { + tocmp+="_"+itos(idx); + } + bool valid=true; + for(int i=0;i<3;i++) { + if (!valid) + break; + for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) { + if (E->get().type!=NODE_SCALAR_INPUT && E->get().type!=NODE_VEC_INPUT && E->get().type==NODE_RGB_INPUT && E->get().type==NODE_XFORM_INPUT && E->get().type==NODE_TEXTURE_INPUT && E->get().type==NODE_CUBEMAP_INPUT) + continue; + String name = E->get().param1; + if (name==tocmp) { + valid=false; + break; + } + + } + } + + if (!valid) { + idx++; + continue; + } + return tocmp; + } + return String(); +} + +void ShaderGraph::node_add(ShaderType p_type, NodeType p_node_type,int p_id) { + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(p_id==0); + ERR_FAIL_COND(p_node_type==NODE_OUTPUT); //can't create output + ERR_FAIL_COND( shader[p_type].node_map.has(p_id ) ); + ERR_FAIL_INDEX( p_node_type, NODE_TYPE_MAX ); Node node; - node.type=p_type; + if (p_node_type==NODE_INPUT) { + //see if it already exists + for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) { + if (E->get().type==NODE_INPUT) { + ERR_EXPLAIN("Only one input node can be added to the graph."); + ERR_FAIL_COND(E->get().type==NODE_INPUT); + } + } + } + node.type=p_node_type; node.id=p_id; - node.x=0; - node.y=0; - node_map[p_id]=node; + switch(p_node_type) { + case NODE_INPUT: {} break; // all inputs (shader type dependent) + case NODE_SCALAR_CONST: { node.param1=0;} break; //scalar constant + case NODE_VEC_CONST: {node.param1=Vector3();} break; //vec3 constant + case NODE_RGB_CONST: {node.param1=Color();} break; //rgb constant (shows a color picker instead) + case NODE_XFORM_CONST: {node.param1=Transform();} break; // 4x4 matrix constant + case NODE_TIME: {} break; // time in seconds + case NODE_SCREEN_TEX: {Array arr; arr.push_back(0); arr.push_back(0); node.param2=arr;} break; // screen texture sampler (takes UV) (only usable in fragment shader) + case NODE_SCALAR_OP: {node.param1=SCALAR_OP_ADD;} break; // scalar vs scalar op (mul: {} break; add: {} break; div: {} break; etc) + case NODE_VEC_OP: {node.param1=VEC_OP_ADD;} break; // vec3 vs vec3 op (mul: {} break;ad: {} break;div: {} break;crossprod: {} break;etc) + case NODE_VEC_SCALAR_OP: {node.param1=VEC_SCALAR_OP_MUL;} break; // vec3 vs scalar op (mul: {} break; add: {} break; div: {} break; etc) + case NODE_RGB_OP: {node.param1=RGB_OP_SCREEN;} break; // vec3 vs vec3 rgb op (with scalar amount): {} break; like brighten: {} break; darken: {} break; burn: {} break; dodge: {} break; multiply: {} break; etc. + case NODE_XFORM_MULT: {} break; // mat4 x mat4 + case NODE_XFORM_VEC_MULT: {} break; // mat4 x vec3 mult (with no-translation option) + case NODE_XFORM_VEC_INV_MULT: {} break; // mat4 x vec3 inverse mult (with no-translation option) + case NODE_SCALAR_FUNC: {node.param1=SCALAR_FUNC_SIN;} break; // scalar function (sin: {} break; cos: {} break; etc) + case NODE_VEC_FUNC: {node.param1=VEC_FUNC_NORMALIZE;} break; // vector function (normalize: {} break; negate: {} break; reciprocal: {} break; rgb2hsv: {} break; hsv2rgb: {} break; etc: {} break; etc) + case NODE_VEC_LEN: {} break; // vec3 length + case NODE_DOT_PROD: {} break; // vec3 . vec3 (dot product -> scalar output) + case NODE_VEC_TO_SCALAR: {} break; // 1 vec3 input: {} break; 3 scalar outputs + case NODE_SCALAR_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output + case NODE_VEC_TO_XFORM: {} break; // 3 scalar input: {} break; 1 vec3 output + case NODE_XFORM_TO_VEC: {} break; // 3 scalar input: {} break; 1 vec3 output + case NODE_SCALAR_INTERP: {} break; // scalar interpolation (with optional curve) + case NODE_VEC_INTERP: {} break; // vec3 interpolation (with optional curve) + case NODE_SCALAR_INPUT: {node.param1=_find_unique_name("Scalar"); node.param2=0;} break; // scalar uniform (assignable in material) + case NODE_VEC_INPUT: {node.param1=_find_unique_name("Vec3");node.param2=Vector3();} break; // vec3 uniform (assignable in material) + case NODE_RGB_INPUT: {node.param1=_find_unique_name("Color");node.param2=Color();} break; // color uniform (assignable in material) + case NODE_XFORM_INPUT: {node.param1=_find_unique_name("XForm"); node.param2=Transform();} break; // mat4 uniform (assignable in material) + case NODE_TEXTURE_INPUT: {node.param1=_find_unique_name("Tex"); } break; // texture input (assignable in material) + case NODE_CUBEMAP_INPUT: {node.param1=_find_unique_name("Cube"); } break; // cubemap input (assignable in material) + case NODE_OUTPUT: {} break; // output (shader type dependent) + case NODE_COMMENT: {} break; // comment + case NODE_TYPE_MAX: {}; + } + shader[p_type].node_map[p_id]=node; + _request_update(); } -void ShaderGraph::node_set_pos(int p_id, const Vector2& p_pos) { +void ShaderGraph::node_set_pos(ShaderType p_type,int p_id, const Vector2& p_pos) { + ERR_FAIL_INDEX(p_type,3); + + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + shader[p_type].node_map[p_id].pos=p_pos; + _request_update(); - ERR_FAIL_COND(!node_map.has(p_id)); - node_map[p_id].x=p_pos.x; - node_map[p_id].y=p_pos.y; } -Vector2 ShaderGraph::node_get_pos(int p_id) const { +Vector2 ShaderGraph::node_get_pos(ShaderType p_type,int p_id) const { + ERR_FAIL_INDEX_V(p_type,3,Vector2()); - ERR_FAIL_COND_V(!node_map.has(p_id),Vector2()); - return Vector2(node_map[p_id].x,node_map[p_id].y); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector2()); + return shader[p_type].node_map[p_id].pos; } -void ShaderGraph::node_remove(int p_id) { +void ShaderGraph::node_remove(ShaderType p_type,int p_id) { + + ERR_FAIL_COND(p_id==0); + ERR_FAIL_INDEX(p_type,3); - ERR_FAIL_COND(!node_map.has(p_id)); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); //erase connections associated with node - List<Connection>::Element *N,*E=connections.front(); - while(E) { - N=E->next(); - const Connection &c = E->get(); - if (c.src_id==p_id || c.dst_id==p_id) { + for(Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) { + if (E->key()==p_id) + continue; //no self + + for (Map<int,SourceSlot>::Element *F=E->get().connections.front();F;) { + Map<int,SourceSlot>::Element *N=F->next(); + + if (F->get().id==p_id) { + E->get().connections.erase(F); + } - connections.erase(E); + F=N; } - E=N; } - node_map.erase(p_id); -} - -void ShaderGraph::node_change_type(int p_id, NodeType p_type) { + shader[p_type].node_map.erase(p_id); - ERR_FAIL_COND(!node_map.has(p_id)); - node_map[p_id].type=p_type; - node_map[p_id].param=Variant(); + _request_update(); } -void ShaderGraph::node_set_param(int p_id, const Variant& p_value) { - ERR_FAIL_COND(!node_map.has(p_id)); - node_map[p_id].param=p_value; -} -void ShaderGraph::get_node_list(List<int> *p_node_list) const { +void ShaderGraph::get_node_list(ShaderType p_type,List<int> *p_node_list) const { - Map<int,Node>::Element *E = node_map.front(); + ERR_FAIL_INDEX(p_type,3); + + Map<int,Node>::Element *E = shader[p_type].node_map.front(); while(E) { @@ -288,740 +595,1463 @@ void ShaderGraph::get_node_list(List<int> *p_node_list) const { } -ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const { +ShaderGraph::NodeType ShaderGraph::node_get_type(ShaderType p_type,int p_id) const { - ERR_FAIL_COND_V(!node_map.has(p_id),NODE_TYPE_MAX); - return node_map[p_id].type; -} + ERR_FAIL_INDEX_V(p_type,3,NODE_TYPE_MAX); -Variant ShaderGraph::node_get_param(int p_id) const { - - ERR_FAIL_COND_V(!node_map.has(p_id),Variant()); - return node_map[p_id].param; + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),NODE_TYPE_MAX); + return shader[p_type].node_map[p_id].type; } -Error ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { +Error ShaderGraph::connect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { + ERR_FAIL_INDEX_V(p_type,3,ERR_INVALID_PARAMETER); ERR_FAIL_COND_V(p_src_id==p_dst_id, ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!node_map.has(p_src_id), ERR_INVALID_PARAMETER); - ERR_FAIL_COND_V(!node_map.has(p_dst_id), ERR_INVALID_PARAMETER); - NodeType type_src=node_map[p_src_id].type; - NodeType type_dst=node_map[p_dst_id].type; - //ERR_FAIL_INDEX_V( p_src_slot, VisualServer::shader_get_output_count(type_src), ERR_INVALID_PARAMETER ); - //ERR_FAIL_INDEX_V( p_dst_slot, VisualServer::shader_get_input_count(type_dst), ERR_INVALID_PARAMETER ); - //ERR_FAIL_COND_V(VisualServer::shader_is_output_vector(type_src,p_src_slot) != VisualServer::shader_is_input_vector(type_dst,p_dst_slot), ERR_INVALID_PARAMETER ); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_src_id), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_dst_id), ERR_INVALID_PARAMETER); + NodeType type_src=shader[p_type].node_map[p_src_id].type; + NodeType type_dst=shader[p_type].node_map[p_dst_id].type; + ERR_FAIL_INDEX_V( p_src_slot, get_node_output_slot_count(get_mode(),p_type,type_src), ERR_INVALID_PARAMETER ); + ERR_FAIL_INDEX_V( p_dst_slot, get_node_input_slot_count(get_mode(),p_type,type_dst), ERR_INVALID_PARAMETER ); + ERR_FAIL_COND_V(get_node_output_slot_type(get_mode(),p_type,type_src,p_src_slot) != get_node_input_slot_type(get_mode(),p_type,type_dst,p_dst_slot), ERR_INVALID_PARAMETER ); - List<Connection>::Element *E=connections.front(); - while(E) { - const Connection &c = E->get(); - ERR_FAIL_COND_V(c.dst_slot==p_dst_slot && c.dst_id == p_dst_id, ERR_ALREADY_EXISTS); + SourceSlot ts; + ts.id=p_src_id; + ts.slot=p_src_slot; + shader[p_type].node_map[p_dst_id].connections[p_dst_slot]=ts; + _request_update(); - E=E->next(); - } + return OK; +} - Connection c; - c.src_slot=p_src_slot; - c.src_id=p_src_id; - c.dst_slot=p_dst_slot; - c.dst_id=p_dst_id; +bool ShaderGraph::is_node_connected(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const { - connections.push_back(c); + ERR_FAIL_INDEX_V(p_type,3,false); - return OK; + SourceSlot ts; + ts.id=p_src_id; + ts.slot=p_src_slot; + return shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) && + shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts; } -bool ShaderGraph::is_connected(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const { +void ShaderGraph::disconnect_node(ShaderType p_type,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { + ERR_FAIL_INDEX(p_type,3); - const List<Connection>::Element *E=connections.front(); - while(E) { - const Connection &c = E->get(); - if (c.dst_slot==p_dst_slot && c.dst_id == p_dst_id && c.src_slot==p_src_slot && c.src_id == p_src_id) - return true; + SourceSlot ts; + ts.id=p_src_id; + ts.slot=p_src_slot; + if (shader[p_type].node_map.has(p_dst_id) && shader[p_type].node_map[p_dst_id].connections.has(p_dst_slot) && + shader[p_type].node_map[p_dst_id].connections[p_dst_slot]==ts) { + shader[p_type].node_map[p_dst_id].connections.erase(p_dst_slot); - E=E->next(); } + _request_update(); - return false; } -void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { +void ShaderGraph::get_node_connections(ShaderType p_type,List<Connection> *p_connections) const { - List<Connection>::Element *N,*E=connections.front(); - while(E) { - N=E->next(); - const Connection &c = E->get(); - if (c.src_slot==p_src_slot && c.src_id==p_src_id && c.dst_slot==p_dst_slot && c.dst_id == p_dst_id) { + ERR_FAIL_INDEX(p_type,3); + + for(const Map<int,Node>::Element *E=shader[p_type].node_map.front();E;E=E->next()) { + for (const Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) { - connections.erase(E); + Connection c; + c.dst_id=E->key(); + c.dst_slot=F->key(); + c.src_id=F->get().id; + c.src_slot=F->get().slot; + p_connections->push_back(c); } - E=N; } +} + + +void ShaderGraph::clear(ShaderType p_type) { + ERR_FAIL_INDEX(p_type,3); + shader[p_type].node_map.clear(); + Node out; + out.pos=Vector2(300,300); + out.type=NODE_OUTPUT; + shader[p_type].node_map.insert(0,out); + + _request_update(); } -void ShaderGraph::get_connections(List<Connection> *p_connections) const { - const List<Connection>::Element*E=connections.front(); - while(E) { - p_connections->push_back(E->get()); - E=E->next(); - } +void ShaderGraph::scalar_const_node_set_value(ShaderType p_type,int p_id,float p_value) { + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_SCALAR_CONST); + n.param1=p_value; + _request_update(); } +float ShaderGraph::scalar_const_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,0); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_SCALAR_CONST,0); + return n.param1; +} + +void ShaderGraph::vec_const_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_VEC_CONST); + n.param1=p_value; + _request_update(); -void ShaderGraph::clear() { - connections.clear(); - node_map.clear(); } +Vector3 ShaderGraph::vec_const_node_get_value(ShaderType p_type,int p_id) const{ + ERR_FAIL_INDEX_V(p_type,3,Vector3()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_VEC_CONST,Vector3()); + return n.param1; -#if 0 -void ShaderGraph::node_add(NodeType p_type,int p_id) { +} + +void ShaderGraph::rgb_const_node_set_value(ShaderType p_type,int p_id,const Color& p_value){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_RGB_CONST); + n.param1=p_value; + _request_update(); - ShaderNode sn; - sn.type=p_type; - nodes[p_id]=sn; - version++; } -void ShaderGraph::node_remove(int p_id) { +Color ShaderGraph::rgb_const_node_get_value(ShaderType p_type,int p_id) const{ - nodes.erase(p_id); + ERR_FAIL_INDEX_V(p_type,3,Color()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_RGB_CONST,Color()); + return n.param1; } -void ShaderGraph::node_set_param( int p_id, const Variant& p_value) { - VisualServer::get_singleton()->shader_node_set_param(shader,p_id,p_value); - version++; +void ShaderGraph::xform_const_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_XFORM_CONST); + n.param1=p_value; + _request_update(); + } +Transform ShaderGraph::xform_const_node_get_value(ShaderType p_type,int p_id) const{ -void ShaderGraph::get_node_list(List<int> *p_node_list) const { + ERR_FAIL_INDEX_V(p_type,3,Transform()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_XFORM_CONST,Transform()); + return n.param1; - VisualServer::get_singleton()->shader_get_node_list(shader,p_node_list); } -ShaderGraph::NodeType ShaderGraph::node_get_type(int p_id) const { - return (NodeType)VisualServer::get_singleton()->shader_node_get_type(shader,p_id); +void ShaderGraph::texture_node_set_filter_size(ShaderType p_type,int p_id,int p_size){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX); + Array arr = n.param2; + arr[0]=p_size; + n.param2=arr; + _request_update(); + } -Variant ShaderGraph::node_get_param(int p_id) const { +int ShaderGraph::texture_node_get_filter_size(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,0); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0); + Array arr = n.param2; + return arr[0]; - return VisualServer::get_singleton()->shader_node_get_param(shader,p_id); } -void ShaderGraph::connect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { +void ShaderGraph::texture_node_set_filter_strength(ShaderType p_type,float p_id,float p_strength){ - VisualServer::get_singleton()->shader_connect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot); - version++; + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX); + Array arr = n.param2; + arr[1]=p_strength; + n.param2=arr; + _request_update(); + +} +float ShaderGraph::texture_node_get_filter_strength(ShaderType p_type,float p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,0); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT && n.type!=NODE_SCREEN_TEX,0); + Array arr = n.param2; + return arr[1]; } -void ShaderGraph::disconnect(int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) { - VisualServer::get_singleton()->shader_disconnect(shader,p_src_id,p_src_slot,p_dst_id,p_dst_slot); - version++; + +void ShaderGraph::scalar_op_node_set_op(ShaderType p_type,float p_id,ScalarOp p_op){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_SCALAR_OP); + n.param1=p_op; + _request_update(); + } +ShaderGraph::ScalarOp ShaderGraph::scalar_op_node_get_op(ShaderType p_type,float p_id) const{ -void ShaderGraph::get_connections(List<Connection> *p_connections) const { + ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_OP); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_OP); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_SCALAR_OP,SCALAR_MAX_OP); + int op = n.param1; + return ScalarOp(op); - List<VS::ShaderGraphConnection> connections; - VisualServer::get_singleton()->shader_get_connections(shader,&connections); - for( List<VS::ShaderGraphConnection>::Element *E=connections.front();E;E=E->next()) { +} + + +void ShaderGraph::vec_op_node_set_op(ShaderType p_type,float p_id,VecOp p_op){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_VEC_OP); + n.param1=p_op; + _request_update(); - Connection c; - c.src_id=E->get().src_id; - c.src_slot=E->get().src_slot; - c.dst_id=E->get().dst_id; - c.dst_slot=E->get().dst_slot; - p_connections->push_back(c); - } } +ShaderGraph::VecOp ShaderGraph::vec_op_node_get_op(ShaderType p_type,float p_id) const{ -void ShaderGraph::node_set_pos(int p_id,const Point2& p_pos) { + ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_OP); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_OP); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_VEC_OP,VEC_MAX_OP); + int op = n.param1; + return VecOp(op); -#ifdef TOOLS_ENABLED - ERR_FAIL_COND(!positions.has(p_id)); - positions[p_id]=p_pos; -#endif } -Point2 ShaderGraph::node_get_pos(int p_id) const { -#ifdef TOOLS_ENABLED - ERR_FAIL_COND_V(!positions.has(p_id),Point2()); - return positions[p_id]; -#endif + +void ShaderGraph::vec_scalar_op_node_set_op(ShaderType p_type,float p_id,VecScalarOp p_op){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_VEC_SCALAR_OP); + n.param1=p_op; + _request_update(); + } +ShaderGraph::VecScalarOp ShaderGraph::vec_scalar_op_node_get_op(ShaderType p_type,float p_id) const{ -void ShaderGraph::clear() { + ERR_FAIL_INDEX_V(p_type,3,VEC_SCALAR_MAX_OP); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_SCALAR_MAX_OP); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_VEC_SCALAR_OP,VEC_SCALAR_MAX_OP); + int op = n.param1; + return VecScalarOp(op); - VisualServer::get_singleton()->shader_clear(shader); - version++; } -#endif -ShaderGraph::ShaderGraph() { +void ShaderGraph::rgb_op_node_set_op(ShaderType p_type,float p_id,RGBOp p_op){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_RGB_OP); + n.param1=p_op; + + _request_update(); - //shader = VisualServer::get_singleton()->shader_create(); - version = 1; } +ShaderGraph::RGBOp ShaderGraph::rgb_op_node_get_op(ShaderType p_type,float p_id) const{ -ShaderGraph::~ShaderGraph() { + ERR_FAIL_INDEX_V(p_type,3,RGB_MAX_OP); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),RGB_MAX_OP); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_RGB_OP,RGB_MAX_OP); + int op = n.param1; + return RGBOp(op); - //VisualServer::get_singleton()->free(shader); } -#if 0 -void ShaderGraph::shader_get_default_input_nodes(Mode p_type,List<PropertyInfo> *p_inputs) { - switch(p_type) { +void ShaderGraph::xform_vec_mult_node_set_no_translation(ShaderType p_type,int p_id,bool p_no_translation){ - case SHADER_VERTEX: { + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT); + n.param1=p_no_translation; + _request_update(); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; - case SHADER_FRAGMENT: { +} +bool ShaderGraph::xform_vec_mult_node_get_no_translation(ShaderType p_type,int p_id) const{ - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"position") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") ); - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); + ERR_FAIL_INDEX_V(p_type,3,false); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),false); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_XFORM_VEC_MULT && n.type!=NODE_XFORM_VEC_INV_MULT,false); + return n.param1; - } break; - case SHADER_POST_PROCESS: { - p_inputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_inputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; +} - } +void ShaderGraph::scalar_func_node_set_function(ShaderType p_type,int p_id,ScalarFunc p_func){ + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_SCALAR_FUNC); + int func = p_func; + ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC); + n.param1=func; + _request_update(); + +} +ShaderGraph::ScalarFunc ShaderGraph::scalar_func_node_get_function(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,SCALAR_MAX_FUNC); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),SCALAR_MAX_FUNC); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_SCALAR_FUNC,SCALAR_MAX_FUNC); + int func = n.param1; + return ScalarFunc(func); } -void ShaderGraph::shader_get_default_output_nodes(ShaderGraphType p_type,List<PropertyInfo> *p_outputs) { - switch(p_type) { +void ShaderGraph::vec_func_node_set_function(ShaderType p_type,int p_id,VecFunc p_func){ - case SHADER_VERTEX: { + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_VEC_FUNC); + int func = p_func; + ERR_FAIL_INDEX(func,VEC_MAX_FUNC); + n.param1=func; - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"vertex") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"binormal") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"tangent") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"uv") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; - case SHADER_FRAGMENT: { + _request_update(); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"normal") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"diffuse") ); - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"specular") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"emission") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"spec_exp") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"glow") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha_discard") ); +} +ShaderGraph::VecFunc ShaderGraph::vec_func_node_get_function(ShaderType p_type, int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,VEC_MAX_FUNC); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),VEC_MAX_FUNC); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_VEC_FUNC,VEC_MAX_FUNC); + int func = n.param1; + return VecFunc(func); +} - } break; - case SHADER_POST_PROCESS: { - p_outputs->push_back( PropertyInfo( Variant::VECTOR3,"color") ); - p_outputs->push_back( PropertyInfo( Variant::REAL,"alpha") ); - } break; +void ShaderGraph::input_node_set_name(ShaderType p_type,int p_id,const String& p_name){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + ERR_FAIL_COND(!p_name.is_valid_identifier()); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT); + + n.param1=""; + n.param1=_find_unique_name(p_name); + _request_update(); + +} +String ShaderGraph::input_node_get_name(ShaderType p_type,int p_id){ + + ERR_FAIL_INDEX_V(p_type,3,String()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT && n.type!=NODE_VEC_INPUT && n.type==NODE_RGB_INPUT && n.type==NODE_XFORM_INPUT && n.type==NODE_TEXTURE_INPUT && n.type==NODE_CUBEMAP_INPUT,String()); + return n.param1; +} + + +void ShaderGraph::scalar_input_node_set_value(ShaderType p_type,int p_id,float p_value) { + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_SCALAR_INPUT); + n.param2=p_value; + _request_update(); + +} + +float ShaderGraph::scalar_input_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,0); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),0); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_SCALAR_INPUT,0); + + return n.param2; +} + +void ShaderGraph::vec_input_node_set_value(ShaderType p_type,int p_id,const Vector3& p_value){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_VEC_INPUT); + + n.param2=p_value; + _request_update(); + +} +Vector3 ShaderGraph::vec_input_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,Vector3()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Vector3()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_VEC_INPUT,Vector3()); + return n.param2; +} + +void ShaderGraph::rgb_input_node_set_value(ShaderType p_type,int p_id,const Color& p_value){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_RGB_INPUT); + n.param2=p_value; + _request_update(); + +} +Color ShaderGraph::rgb_input_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,Color()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Color()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_RGB_INPUT,Color()); + return n.param2; +} + +void ShaderGraph::xform_input_node_set_value(ShaderType p_type,int p_id,const Transform& p_value){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_XFORM_INPUT); + n.param2=p_value; + _request_update(); + +} +Transform ShaderGraph::xform_input_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,Transform()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Transform()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_XFORM_INPUT,Transform()); + return n.param2; +} + + +void ShaderGraph::texture_input_node_set_value(ShaderType p_type,int p_id,const Ref<Texture>& p_texture) { + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_TEXTURE_INPUT); + n.param2=p_texture; + _request_update(); +} + +Ref<Texture> ShaderGraph::texture_input_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,Ref<Texture>()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<Texture>()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_TEXTURE_INPUT,Ref<Texture>()); + return n.param2; +} + +void ShaderGraph::cubemap_input_node_set_value(ShaderType p_type,int p_id,const Ref<CubeMap>& p_cubemap){ + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_CUBEMAP_INPUT); + n.param2=p_cubemap; + _request_update(); + +} + +Ref<CubeMap> ShaderGraph::cubemap_input_node_get_value(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,Ref<CubeMap>()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Ref<CubeMap>()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_CUBEMAP_INPUT,Ref<CubeMap>()); + return n.param2; + +} + + +void ShaderGraph::comment_node_set_text(ShaderType p_type,int p_id,const String& p_comment) { + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND(n.type!=NODE_COMMENT); + n.param1=p_comment; + +} + +String ShaderGraph::comment_node_get_text(ShaderType p_type,int p_id) const{ + + ERR_FAIL_INDEX_V(p_type,3,String()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),String()); + const Node& n = shader[p_type].node_map[p_id]; + ERR_FAIL_COND_V(n.type!=NODE_COMMENT,String()); + return n.param1; + +} + +void ShaderGraph::_request_update() { + + if (_pending_update_shader) + return; + + _pending_update_shader=true; + call_deferred("_update_shader"); + +} + +Variant ShaderGraph::node_get_state(ShaderType p_type,int p_id) const { + + ERR_FAIL_INDEX_V(p_type,3,Variant()); + ERR_FAIL_COND_V(!shader[p_type].node_map.has(p_id),Variant()); + const Node& n = shader[p_type].node_map[p_id]; + Dictionary s; + s["pos"]=n.pos; + s["param1"]=n.param1; + s["param2"]=n.param2; + return s; + +} +void ShaderGraph::node_set_state(ShaderType p_type,int p_id,const Variant& p_state) { + + ERR_FAIL_INDEX(p_type,3); + ERR_FAIL_COND(!shader[p_type].node_map.has(p_id)); + Node& n = shader[p_type].node_map[p_id]; + Dictionary d = p_state; + ERR_FAIL_COND(!d.has("pos")); + ERR_FAIL_COND(!d.has("param1")); + ERR_FAIL_COND(!d.has("param2")); + n.pos=d["pos"]; + n.param1=d["param1"]; + n.param2=d["param2"]; + +} + +ShaderGraph::ShaderGraph(Mode p_mode) : Shader(p_mode) { + + //shader = VisualServer::get_singleton()->shader_create(); + _pending_update_shader=false; + Node out; + out.id=0; + out.pos=Vector2(250,20); + out.type=NODE_OUTPUT; + for(int i=0;i<3;i++) { + + shader[i].node_map.insert(0,out); } +} + +ShaderGraph::~ShaderGraph() { + //VisualServer::get_singleton()->free(shader); +} + + +const ShaderGraph::InOutParamInfo ShaderGraph::inout_param_info[]={ + //material vertex in + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","SRC_VERTEX","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","SRC_NORMAL","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","SRC_TANGENT","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"BinormalF","SRC_BINORMALF","",SLOT_TYPE_SCALAR,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","SRC_COLOR","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","SRC_ALPHA","",SLOT_TYPE_SCALAR,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","SRC_UV","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","SRC_UV2","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"WorldMatrix","WORLD_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ProjectionMatrix","PROJECTION_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"ModelviewMatrix","MODELVIEW_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"InstanceID","INSTANCE_ID","",SLOT_TYPE_SCALAR,SLOT_IN}, + + //material vertex out + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV","UV",".xy",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"UV2","UV2",".xy",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"SpecExp","SPEC_EXP","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_VERTEX,"PointSize","POINT_SIZE","",SLOT_TYPE_SCALAR,SLOT_OUT}, + //pixel vertex in + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Vertex","VERTEX","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Position","POSITION.xyz","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","IN_NORMAL","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Tangent","TANGENT","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Binormal","BINORMAL","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV","vec3(UV,0);","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UV2","UV2","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"UVScreen","SCREEN_UV","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"PointCoord","POINT_COORD","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Color","COLOR.rgb","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Alpha","COLOR.a","",SLOT_TYPE_SCALAR,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"InvCameraMatrix","INV_CAMERA_MATRIX","",SLOT_TYPE_XFORM,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var1","VAR1.rgb","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Var2","VAR2.rgb","",SLOT_TYPE_VEC,SLOT_IN}, + //pixel vertex out + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Diffuse","DIFFUSE_OUT","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"DiffuseAlpha","ALPHA_OUT","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"SpecularExp","SPECULAR","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Emission","EMISSION","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Glow","GLOW","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMap","NORMALMAP","",SLOT_TYPE_VEC,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"NormalMapDepth","NORMALMAP_DEPTH","",SLOT_TYPE_SCALAR,SLOT_OUT}, + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,"Discard","DISCARD",">0.5",SLOT_TYPE_SCALAR,SLOT_OUT}, + //light in + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Normal","NORMAL","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDir","LIGHT_DIR","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightDiffuse","LIGHT_DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"LightSpecular","LIGHT_SPECULAR","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"EyeVec","EYE_VEC","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Diffuse","DIFFUSE","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Specular","SPECULAR","",SLOT_TYPE_VEC,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"SpecExp","SPECULAR_EXP","",SLOT_TYPE_SCALAR,SLOT_IN}, + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"ShadeParam","SHADE_PARAM","",SLOT_TYPE_SCALAR,SLOT_IN}, + //light out + {MODE_MATERIAL,SHADER_TYPE_LIGHT,"Light","LIGHT","",SLOT_TYPE_VEC,SLOT_OUT}, + //end + {MODE_MATERIAL,SHADER_TYPE_FRAGMENT,NULL,NULL,NULL,SLOT_TYPE_SCALAR,SLOT_OUT}, + +}; + +void ShaderGraph::get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots) { + + const InOutParamInfo* iop = &inout_param_info[0]; + while(iop->name) { + if (p_mode==iop->shader_mode && p_type==iop->shader_type) { + + SlotInfo si; + si.dir=iop->dir; + si.name=iop->name; + si.type=iop->slot_type; + r_slots->push_back(si); + } + iop++; + } } -PropertyInfo ShaderGraph::shader_node_get_type_info(NodeType p_type) { - - switch(p_type) { - - case NODE_IN: return PropertyInfo(Variant::STRING,"in"); - case NODE_OUT: return PropertyInfo(Variant::STRING,"out"); - case NODE_CONSTANT: return PropertyInfo(Variant::REAL,"const"); - case NODE_PARAMETER: return PropertyInfo(Variant::STRING,"param"); - case NODE_ADD: return PropertyInfo(Variant::NIL,"add"); - case NODE_SUB: return PropertyInfo(Variant::NIL,"sub"); - case NODE_MUL: return PropertyInfo(Variant::NIL,"mul"); - case NODE_DIV: return PropertyInfo(Variant::NIL,"div"); - case NODE_MOD: return PropertyInfo(Variant::NIL,"rem"); - case NODE_SIN: return PropertyInfo(Variant::NIL,"sin"); - case NODE_COS: return PropertyInfo(Variant::NIL,"cos"); - case NODE_TAN: return PropertyInfo(Variant::NIL,"tan"); - case NODE_ARCSIN: return PropertyInfo(Variant::NIL,"arcsin"); - case NODE_ARCCOS: return PropertyInfo(Variant::NIL,"arccos"); - case NODE_ARCTAN: return PropertyInfo(Variant::NIL,"arctan"); - case NODE_POW: return PropertyInfo(Variant::NIL,"pow"); - case NODE_LOG: return PropertyInfo(Variant::NIL,"log"); - case NODE_MAX: return PropertyInfo(Variant::NIL,"max"); - case NODE_MIN: return PropertyInfo(Variant::NIL,"min"); - case NODE_COMPARE: return PropertyInfo(Variant::NIL,"cmp"); - case NODE_TEXTURE: return PropertyInfo(Variant::_RID,"texture1D",PROPERTY_HINT_RESOURCE_TYPE,"Texture"); - case NODE_TIME: return PropertyInfo(Variant::NIL,"time"); - case NODE_NOISE: return PropertyInfo(Variant::NIL,"noise"); - case NODE_PASS: return PropertyInfo(Variant::NIL,"pass"); - case NODE_VEC_IN: return PropertyInfo(Variant::STRING,"vin"); - case NODE_VEC_OUT: return PropertyInfo(Variant::STRING,"vout"); - case NODE_VEC_CONSTANT: return PropertyInfo(Variant::VECTOR3,"vconst"); - case NODE_VEC_PARAMETER: return PropertyInfo(Variant::STRING,"vparam"); - case NODE_VEC_ADD: return PropertyInfo(Variant::NIL,"vadd"); - case NODE_VEC_SUB: return PropertyInfo(Variant::NIL,"vsub"); - case NODE_VEC_MUL: return PropertyInfo(Variant::NIL,"vmul"); - case NODE_VEC_DIV: return PropertyInfo(Variant::NIL,"vdiv"); - case NODE_VEC_MOD: return PropertyInfo(Variant::NIL,"vrem"); - case NODE_VEC_CROSS: return PropertyInfo(Variant::NIL,"cross"); - case NODE_VEC_DOT: return PropertyInfo(Variant::NIL,"dot"); - case NODE_VEC_POW: return PropertyInfo(Variant::NIL,"vpow"); - case NODE_VEC_NORMALIZE: return PropertyInfo(Variant::NIL,"normalize"); - case NODE_VEC_INTERPOLATE: return PropertyInfo(Variant::NIL,"mix"); - case NODE_VEC_SCREEN_TO_UV: return PropertyInfo(Variant::NIL,"scrn2uv"); - case NODE_VEC_TRANSFORM3: return PropertyInfo(Variant::NIL,"xform3"); - case NODE_VEC_TRANSFORM4: return PropertyInfo(Variant::NIL,"xform4"); - case NODE_VEC_COMPARE: return PropertyInfo(Variant::_RID,"vcmp",PROPERTY_HINT_RESOURCE_TYPE,"Texture"); - case NODE_VEC_TEXTURE_2D: return PropertyInfo(Variant::_RID,"texture2D",PROPERTY_HINT_RESOURCE_TYPE,"Texture"); - case NODE_VEC_TEXTURE_CUBE: return PropertyInfo(Variant::NIL,"texcube"); - case NODE_VEC_NOISE: return PropertyInfo(Variant::NIL,"vec_noise"); - case NODE_VEC_0: return PropertyInfo(Variant::NIL,"vec_0"); - case NODE_VEC_1: return PropertyInfo(Variant::NIL,"vec_1"); - case NODE_VEC_2: return PropertyInfo(Variant::NIL,"vec_2"); - case NODE_VEC_BUILD: return PropertyInfo(Variant::NIL,"vbuild"); - case NODE_VEC_PASS: return PropertyInfo(Variant::NIL,"vpass"); - case NODE_COLOR_CONSTANT: return PropertyInfo(Variant::COLOR,"color_const"); - case NODE_COLOR_PARAMETER: return PropertyInfo(Variant::STRING,"color_param"); - case NODE_TEXTURE_PARAMETER: return PropertyInfo(Variant::STRING,"tex1D_param"); - case NODE_TEXTURE_2D_PARAMETER: return PropertyInfo(Variant::STRING,"tex2D_param"); - case NODE_TEXTURE_CUBE_PARAMETER: return PropertyInfo(Variant::STRING,"texcube_param"); - case NODE_TRANSFORM_CONSTANT: return PropertyInfo(Variant::TRANSFORM,"xform_const"); - case NODE_TRANSFORM_PARAMETER: return PropertyInfo(Variant::STRING,"xform_param"); - case NODE_LABEL: return PropertyInfo(Variant::STRING,"label"); - - default: {} +const ShaderGraph::NodeSlotInfo ShaderGraph::node_slot_info[]= { + + {NODE_SCALAR_CONST,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, //scalar constant + {NODE_VEC_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, //vec3 constant + {NODE_RGB_CONST,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, //rgb constant (shows a color picker instead) + {NODE_XFORM_CONST,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // 4x4 matrix constant + {NODE_TIME,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // time in seconds + {NODE_SCREEN_TEX,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // screen texture sampler (takes UV) (only usable in fragment shader) + {NODE_SCALAR_OP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) + {NODE_VEC_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // scalar vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) + {NODE_VEC_SCALAR_OP,{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) + {NODE_RGB_OP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 vs scalar op (mul,{SLOT_MAX},{SLOT_MAX}}, add,{SLOT_MAX},{SLOT_MAX}}, div,{SLOT_MAX},{SLOT_MAX}}, etc) + {NODE_XFORM_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 x mat4 + {NODE_XFORM_VEC_MULT,{SLOT_TYPE_XFORM,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 mult (with no-translation option) + {NODE_XFORM_VEC_INV_MULT,{SLOT_TYPE_VEC,SLOT_TYPE_XFORM,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // mat4 x vec3 inverse mult (with no-translation option) + {NODE_SCALAR_FUNC,{SLOT_TYPE_SCALAR,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar function (sin,{SLOT_MAX},{SLOT_MAX}}, cos,{SLOT_MAX},{SLOT_MAX}}, etc) + {NODE_VEC_FUNC,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vector function (normalize,{SLOT_MAX},{SLOT_MAX}}, negate,{SLOT_MAX},{SLOT_MAX}}, reciprocal,{SLOT_MAX},{SLOT_MAX}}, rgb2hsv,{SLOT_MAX},{SLOT_MAX}}, hsv2rgb,{SLOT_MAX},{SLOT_MAX}}, etc,{SLOT_MAX},{SLOT_MAX}}, etc) + {NODE_VEC_LEN,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 length + {NODE_DOT_PROD,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // vec3 . vec3 (dot product -> scalar output) + {NODE_VEC_TO_SCALAR,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR}}, // 1 vec3 input,{SLOT_MAX},{SLOT_MAX}}, 3 scalar outputs + {NODE_SCALAR_TO_VEC,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // 3 scalar input,{SLOT_MAX},{SLOT_MAX}}, 1 vec3 output + {NODE_SCALAR_INTERP,{SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR,SLOT_TYPE_SCALAR},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar interpolation (with optional curve) + {NODE_VEC_INTERP,{SLOT_TYPE_VEC,SLOT_TYPE_VEC,SLOT_TYPE_SCALAR},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 interpolation (with optional curve) + {NODE_SCALAR_INPUT,{SLOT_MAX},{SLOT_TYPE_SCALAR,SLOT_MAX}}, // scalar uniform (assignable in material) + {NODE_VEC_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // vec3 uniform (assignable in material) + {NODE_RGB_INPUT,{SLOT_MAX},{SLOT_TYPE_VEC,SLOT_MAX}}, // color uniform (assignable in material) + {NODE_XFORM_INPUT,{SLOT_MAX},{SLOT_TYPE_XFORM,SLOT_MAX}}, // mat4 uniform (assignable in material) + {NODE_TEXTURE_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // texture input (assignable in material) + {NODE_CUBEMAP_INPUT,{SLOT_TYPE_VEC,SLOT_MAX},{SLOT_TYPE_VEC,SLOT_TYPE_SCALAR,SLOT_MAX}}, // cubemap input (assignable in material) + {NODE_COMMENT,{SLOT_MAX},{SLOT_MAX}}, // comment + {NODE_TYPE_MAX,{SLOT_MAX},{SLOT_MAX}} +}; + +int ShaderGraph::get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type) { + + if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) { + + const InOutParamInfo* iop = &inout_param_info[0]; + int pc=0; + while(iop->name) { + if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) { + + if (iop->dir==SLOT_OUT) + pc++; + } + iop++; + } + return pc; + } else if (p_type==NODE_VEC_TO_XFORM){ + return 4; + } else if (p_type==NODE_XFORM_TO_VEC){ + return 1; + } else { + + const NodeSlotInfo*nsi=&node_slot_info[0]; + while(nsi->type!=NODE_TYPE_MAX) { + + if (nsi->type==p_type) { + int pc=0; + for(int i=0;i<NodeSlotInfo::MAX_INS;i++) { + if (nsi->ins[i]==SLOT_MAX) + break; + pc++; + } + return pc; + } + + nsi++; + } + + return 0; } +} + +int ShaderGraph::get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type){ + + if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) { + + const InOutParamInfo* iop = &inout_param_info[0]; + int pc=0; + while(iop->name) { + if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) { + + if (iop->dir==SLOT_IN) + pc++; + } + iop++; + } + return pc; + } else if (p_type==NODE_VEC_TO_XFORM){ + return 1; + } else if (p_type==NODE_XFORM_TO_VEC){ + return 4; + } else { + + const NodeSlotInfo*nsi=&node_slot_info[0]; + while(nsi->type!=NODE_TYPE_MAX) { + + if (nsi->type==p_type) { + int pc=0; + for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) { + if (nsi->outs[i]==SLOT_MAX) + break; + pc++; + } + return pc; + } + + nsi++; + } + + return 0; - ERR_FAIL_V( PropertyInfo(Variant::NIL,"error") ); -} -int ShaderGraph::shader_get_input_count(NodeType p_type) { - - switch(p_type) { - case NODE_IN: return 0; - case NODE_OUT: return 1; - case NODE_CONSTANT: return 0; - case NODE_PARAMETER: return 0; - case NODE_ADD: return 2; - case NODE_SUB: return 2; - case NODE_MUL: return 2; - case NODE_DIV: return 2; - case NODE_MOD: return 2; - case NODE_SIN: return 1; - case NODE_COS: return 1; - case NODE_TAN: return 1; - case NODE_ARCSIN: return 1; - case NODE_ARCCOS: return 1; - case NODE_ARCTAN: return 1; - case NODE_POW: return 2; - case NODE_LOG: return 1; - case NODE_MAX: return 2; - case NODE_MIN: return 2; - case NODE_COMPARE: return 4; - case NODE_TEXTURE: return 1; ///< param 0: texture - case NODE_TIME: return 1; ///< param 0: interval length - case NODE_NOISE: return 0; - case NODE_PASS: return 1; - case NODE_VEC_IN: return 0; ///< param 0: name - case NODE_VEC_OUT: return 1; ///< param 0: name - case NODE_VEC_CONSTANT: return 0; ///< param 0: value - case NODE_VEC_PARAMETER: return 0; ///< param 0: name - case NODE_VEC_ADD: return 2; - case NODE_VEC_SUB: return 2; - case NODE_VEC_MUL: return 2; - case NODE_VEC_DIV: return 2; - case NODE_VEC_MOD: return 2; - case NODE_VEC_CROSS: return 2; - case NODE_VEC_DOT: return 2; - case NODE_VEC_POW: return 2; - case NODE_VEC_NORMALIZE: return 1; - case NODE_VEC_INTERPOLATE: return 3; - case NODE_VEC_SCREEN_TO_UV: return 1; - case NODE_VEC_TRANSFORM3: return 4; - case NODE_VEC_TRANSFORM4: return 5; - case NODE_VEC_COMPARE: return 4; - case NODE_VEC_TEXTURE_2D: return 1; - case NODE_VEC_TEXTURE_CUBE: return 1; - case NODE_VEC_NOISE: return 0; - case NODE_VEC_0: return 1; - case NODE_VEC_1: return 1; - case NODE_VEC_2: return 1; - case NODE_VEC_BUILD: return 3; - case NODE_VEC_PASS: return 1; - case NODE_COLOR_CONSTANT: return 0; - case NODE_COLOR_PARAMETER: return 0; - case NODE_TEXTURE_PARAMETER: return 1; - case NODE_TEXTURE_2D_PARAMETER: return 1; - case NODE_TEXTURE_CUBE_PARAMETER: return 1; - case NODE_TRANSFORM_CONSTANT: return 1; - case NODE_TRANSFORM_PARAMETER: return 1; - case NODE_LABEL: return 0; - default: {} } - ERR_FAIL_V( 0 ); -} -int ShaderGraph::shader_get_output_count(NodeType p_type) { - - switch(p_type) { - case NODE_IN: return 1; - case NODE_OUT: return 0; - case NODE_CONSTANT: return 1; - case NODE_PARAMETER: return 1; - case NODE_ADD: return 1; - case NODE_SUB: return 1; - case NODE_MUL: return 1; - case NODE_DIV: return 1; - case NODE_MOD: return 1; - case NODE_SIN: return 1; - case NODE_COS: return 1; - case NODE_TAN: return 1; - case NODE_ARCSIN: return 1; - case NODE_ARCCOS: return 1; - case NODE_ARCTAN: return 1; - case NODE_POW: return 1; - case NODE_LOG: return 1; - case NODE_MAX: return 1; - case NODE_MIN: return 1; - case NODE_COMPARE: return 2; - case NODE_TEXTURE: return 3; ///< param 0: texture - case NODE_TIME: return 1; ///< param 0: interval length - case NODE_NOISE: return 1; - case NODE_PASS: return 1; - case NODE_VEC_IN: return 1; ///< param 0: name - case NODE_VEC_OUT: return 0; ///< param 0: name - case NODE_VEC_CONSTANT: return 1; ///< param 0: value - case NODE_VEC_PARAMETER: return 1; ///< param 0: name - case NODE_VEC_ADD: return 1; - case NODE_VEC_SUB: return 1; - case NODE_VEC_MUL: return 1; - case NODE_VEC_DIV: return 1; - case NODE_VEC_MOD: return 1; - case NODE_VEC_CROSS: return 1; - case NODE_VEC_DOT: return 1; - case NODE_VEC_POW: return 1; - case NODE_VEC_NORMALIZE: return 1; - case NODE_VEC_INTERPOLATE: return 1; - case NODE_VEC_SCREEN_TO_UV: return 1; - case NODE_VEC_TRANSFORM3: return 1; - case NODE_VEC_TRANSFORM4: return 1; - case NODE_VEC_COMPARE: return 2; - case NODE_VEC_TEXTURE_2D: return 3; - case NODE_VEC_TEXTURE_CUBE: return 3; - case NODE_VEC_NOISE: return 1; - case NODE_VEC_0: return 1; - case NODE_VEC_1: return 1; - case NODE_VEC_2: return 1; - case NODE_VEC_BUILD: return 1; - case NODE_VEC_PASS: return 1; - case NODE_COLOR_CONSTANT: return 2; - case NODE_COLOR_PARAMETER: return 2; - case NODE_TEXTURE_PARAMETER: return 3; - case NODE_TEXTURE_2D_PARAMETER: return 3; - case NODE_TEXTURE_CUBE_PARAMETER: return 3; - case NODE_TRANSFORM_CONSTANT: return 1; - case NODE_TRANSFORM_PARAMETER: return 1; - case NODE_LABEL: return 0; - - default: {} +} +ShaderGraph::SlotType ShaderGraph::get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){ + + if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) { + + const InOutParamInfo* iop = &inout_param_info[0]; + int pc=0; + while(iop->name) { + if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) { + + if (iop->dir==SLOT_OUT) { + if (pc==p_idx) + return iop->slot_type; + pc++; + } + } + iop++; + } + ERR_FAIL_V(SLOT_MAX); + } else if (p_type==NODE_VEC_TO_XFORM){ + return SLOT_TYPE_VEC; + } else if (p_type==NODE_XFORM_TO_VEC){ + return SLOT_TYPE_XFORM; + } else { + + const NodeSlotInfo*nsi=&node_slot_info[0]; + while(nsi->type!=NODE_TYPE_MAX) { + + if (nsi->type==p_type) { + for(int i=0;i<NodeSlotInfo::MAX_INS;i++) { + + if (nsi->ins[i]==SLOT_MAX) + break; + if (i==p_idx) + return nsi->ins[i]; + } + } + + nsi++; + } + + ERR_FAIL_V(SLOT_MAX); + } - ERR_FAIL_V( 0 ); - -} - -#define RET2(m_a,m_b) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else return ""; -#define RET3(m_a,m_b,m_c) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else return ""; -#define RET4(m_a,m_b,m_c,m_d) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else return ""; - -#define RET5(m_a,m_b,m_c,m_d,m_e) if (p_idx==0) return m_a; else if (p_idx==1) return m_b; else if (p_idx==2) return m_c; else if (p_idx==3) return m_d; else if (p_idx==4) return m_e; else return ""; - -String ShaderGraph::shader_get_input_name(NodeType p_type,int p_idx) { - - switch(p_type) { - - case NODE_IN: return ""; - case NODE_OUT: return "out"; - case NODE_CONSTANT: return ""; - case NODE_PARAMETER: return ""; - case NODE_ADD: RET2("a","b"); - case NODE_SUB: RET2("a","b"); - case NODE_MUL: RET2("a","b"); - case NODE_DIV: RET2("a","b"); - case NODE_MOD: RET2("a","b"); - case NODE_SIN: return "rad"; - case NODE_COS: return "rad"; - case NODE_TAN: return "rad"; - case NODE_ARCSIN: return "in"; - case NODE_ARCCOS: return "in"; - case NODE_ARCTAN: return "in"; - case NODE_POW: RET2("in","exp"); - case NODE_LOG: return "in"; - case NODE_MAX: return "in"; - case NODE_MIN: return "in"; - case NODE_COMPARE: RET4("a","b","ret1","ret2"); - case NODE_TEXTURE: return "u"; - case NODE_TIME: return ""; - case NODE_NOISE: return ""; - case NODE_PASS: return "in"; - case NODE_VEC_IN: return ""; - case NODE_VEC_OUT: return "out"; - case NODE_VEC_CONSTANT: return ""; - case NODE_VEC_PARAMETER: return ""; - case NODE_VEC_ADD: RET2("a","b"); - case NODE_VEC_SUB: RET2("a","b"); - case NODE_VEC_MUL: RET2("a","b"); - case NODE_VEC_DIV: RET2("a","b"); - case NODE_VEC_MOD: RET2("a","b"); - case NODE_VEC_CROSS: RET2("a","b"); - case NODE_VEC_DOT: RET2("a","b"); - case NODE_VEC_POW: RET2("a","b"); - case NODE_VEC_NORMALIZE: return "vec"; - case NODE_VEC_INTERPOLATE: RET3("a","b","c"); - case NODE_VEC_SCREEN_TO_UV: return "scr"; - case NODE_VEC_TRANSFORM3: RET4("in","col0","col1","col2"); - case NODE_VEC_TRANSFORM4: RET5("in","col0","col1","col2","col3"); - case NODE_VEC_COMPARE: RET4("a","b","ret1","ret2"); - case NODE_VEC_TEXTURE_2D: return "uv"; - case NODE_VEC_TEXTURE_CUBE: return "uvw"; - case NODE_VEC_NOISE: return ""; - case NODE_VEC_0: return "vec"; - case NODE_VEC_1: return "vec"; - case NODE_VEC_2: return "vec"; - case NODE_VEC_BUILD: RET3("x/r","y/g","z/b"); - case NODE_VEC_PASS: return "in"; - case NODE_COLOR_CONSTANT: return ""; - case NODE_COLOR_PARAMETER: return ""; - case NODE_TEXTURE_PARAMETER: return "u"; - case NODE_TEXTURE_2D_PARAMETER: return "uv"; - case NODE_TEXTURE_CUBE_PARAMETER: return "uvw"; - case NODE_TRANSFORM_CONSTANT: return "in"; - case NODE_TRANSFORM_PARAMETER: return "in"; - case NODE_LABEL: return ""; - - default: {} +} +ShaderGraph::SlotType ShaderGraph::get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx){ + + if (p_type==NODE_INPUT || p_type==NODE_OUTPUT) { + + const InOutParamInfo* iop = &inout_param_info[0]; + int pc=0; + while(iop->name) { + if (p_mode==iop->shader_mode && p_shader_type==iop->shader_type) { + + if (iop->dir==SLOT_IN) { + if (pc==p_idx) + return iop->slot_type; + pc++; + } + } + iop++; + } + ERR_FAIL_V(SLOT_MAX); + } else if (p_type==NODE_VEC_TO_XFORM){ + return SLOT_TYPE_XFORM; + } else if (p_type==NODE_XFORM_TO_VEC){ + return SLOT_TYPE_VEC; + } else { + + const NodeSlotInfo*nsi=&node_slot_info[0]; + while(nsi->type!=NODE_TYPE_MAX) { + + if (nsi->type==p_type) { + for(int i=0;i<NodeSlotInfo::MAX_OUTS;i++) { + if (nsi->outs[i]==SLOT_MAX) + break; + if (i==p_idx) + return nsi->outs[i]; + } + } + + nsi++; + } + + ERR_FAIL_V(SLOT_MAX); } +} + + - ERR_FAIL_V(""); -} -String ShaderGraph::shader_get_output_name(NodeType p_type,int p_idx) { - - switch(p_type) { - - case NODE_IN: return "in"; - case NODE_OUT: return ""; - case NODE_CONSTANT: return "out"; - case NODE_PARAMETER: return "out"; - case NODE_ADD: return "sum"; - case NODE_SUB: return "dif"; - case NODE_MUL: return "prod"; - case NODE_DIV: return "quot"; - case NODE_MOD: return "rem"; - case NODE_SIN: return "out"; - case NODE_COS: return "out"; - case NODE_TAN: return "out"; - case NODE_ARCSIN: return "rad"; - case NODE_ARCCOS: return "rad"; - case NODE_ARCTAN: return "rad"; - case NODE_POW: RET2("in","exp"); - case NODE_LOG: return "out"; - case NODE_MAX: return "out"; - case NODE_MIN: return "out"; - case NODE_COMPARE: RET2("a/b","a/b"); - case NODE_TEXTURE: RET3("rgb","a","v"); - case NODE_TIME: return "out"; - case NODE_NOISE: return "out"; - case NODE_PASS: return "out"; - case NODE_VEC_IN: return "in"; - case NODE_VEC_OUT: return ""; - case NODE_VEC_CONSTANT: return "out"; - case NODE_VEC_PARAMETER: return "out"; - case NODE_VEC_ADD: return "sum"; - case NODE_VEC_SUB: return "sub"; - case NODE_VEC_MUL: return "mul"; - case NODE_VEC_DIV: return "div"; - case NODE_VEC_MOD: return "rem"; - case NODE_VEC_CROSS: return "crs"; - case NODE_VEC_DOT: return "prod"; - case NODE_VEC_POW: return "out"; - case NODE_VEC_NORMALIZE: return "norm"; - case NODE_VEC_INTERPOLATE: return "out"; - case NODE_VEC_SCREEN_TO_UV: return "uv"; - case NODE_VEC_TRANSFORM3: return "prod"; - case NODE_VEC_TRANSFORM4: return "prod"; - case NODE_VEC_COMPARE: RET2("a/b","a/b"); - case NODE_VEC_TEXTURE_2D: RET3("rgb","a","v"); - case NODE_VEC_TEXTURE_CUBE: RET3("rgb","a","v"); - case NODE_VEC_NOISE: return "out"; - case NODE_VEC_0: return "x/r"; - case NODE_VEC_1: return "y/g"; - case NODE_VEC_2: return "z/b"; - case NODE_VEC_BUILD: return "vec"; - case NODE_VEC_PASS: return "out"; - case NODE_COLOR_CONSTANT: RET2("rgb","a"); - case NODE_COLOR_PARAMETER: RET2("rgb","a"); - case NODE_TEXTURE_PARAMETER: RET3("rgb","a","v"); - case NODE_TEXTURE_2D_PARAMETER: RET3("rgb","a","v"); - case NODE_TEXTURE_CUBE_PARAMETER: RET3("rgb","a","v"); - case NODE_TRANSFORM_CONSTANT: return "out"; - case NODE_TRANSFORM_PARAMETER: return "out"; - case NODE_LABEL: return ""; - - default: {} + + +void ShaderGraph::_update_shader() { + + + String code[3]; + + List<StringName> names; + get_default_texture_param_list(&names); + + for (List<StringName>::Element *E=names.front();E;E=E->next()) { + set_default_texture_param(E->get(),Ref<Texture>()); } - ERR_FAIL_V(""); -} -bool ShaderGraph::shader_is_input_vector(NodeType p_type,int p_input) { - - switch(p_type) { - - case NODE_IN: return false; - case NODE_OUT: return false; - case NODE_CONSTANT: return false; - case NODE_PARAMETER: return false; - case NODE_ADD: return false; - case NODE_SUB: return false; - case NODE_MUL: return false; - case NODE_DIV: return false; - case NODE_MOD: return false; - case NODE_SIN: return false; - case NODE_COS: return false; - case NODE_TAN: return false; - case NODE_ARCSIN: return false; - case NODE_ARCCOS: return false; - case NODE_ARCTAN: return false; - case NODE_POW: return false; - case NODE_LOG: return false; - case NODE_MAX: return false; - case NODE_MIN: return false; - case NODE_COMPARE: return false; - case NODE_TEXTURE: return false; - case NODE_TIME: return false; - case NODE_NOISE: return false; - case NODE_PASS: return false; - case NODE_VEC_IN: return false; - case NODE_VEC_OUT: return true; - case NODE_VEC_CONSTANT: return false; - case NODE_VEC_PARAMETER: return false; - case NODE_VEC_ADD: return true; - case NODE_VEC_SUB: return true; - case NODE_VEC_MUL: return true; - case NODE_VEC_DIV: return true; - case NODE_VEC_MOD: return true; - case NODE_VEC_CROSS: return true; - case NODE_VEC_DOT: return true; - case NODE_VEC_POW: return (p_input==0)?true:false; - case NODE_VEC_NORMALIZE: return true; - case NODE_VEC_INTERPOLATE: return (p_input<2)?true:false; - case NODE_VEC_SCREEN_TO_UV: return true; - case NODE_VEC_TRANSFORM3: return true; - case NODE_VEC_TRANSFORM4: return true; - case NODE_VEC_COMPARE: return (p_input<2)?false:true; - case NODE_VEC_TEXTURE_2D: return true; - case NODE_VEC_TEXTURE_CUBE: return true; - case NODE_VEC_NOISE: return false; - case NODE_VEC_0: return true; - case NODE_VEC_1: return true; - case NODE_VEC_2: return true; - case NODE_VEC_BUILD: return false; - case NODE_VEC_PASS: return true; - case NODE_COLOR_CONSTANT: return false; - case NODE_COLOR_PARAMETER: return false; - case NODE_TEXTURE_PARAMETER: return false; - case NODE_TEXTURE_2D_PARAMETER: return true; - case NODE_TEXTURE_CUBE_PARAMETER: return true; - case NODE_TRANSFORM_CONSTANT: return true; - case NODE_TRANSFORM_PARAMETER: return true; - case NODE_LABEL: return false; - - default: {} + + for(int i=0;i<3;i++) { + + int idx=0; + for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) { + + E->get().sort_order=idx++; + } + //simple method for graph solving using bubblesort derived algorithm + int iters=0; + int iter_max=shader[i].node_map.size()*shader[i].node_map.size(); + + while(true) { + if (iters>iter_max) + break; + + int swaps=0; + for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) { + + for(Map<int,SourceSlot>::Element *F=E->get().connections.front();F;F=F->next()) { + + //this is kinda slow, could be sped up + Map<int,Node>::Element *G = shader[i].node_map.find(F->get().id); + ERR_FAIL_COND(!G); + if (G->get().sort_order > E->get().sort_order) { + + SWAP(G->get().sort_order,E->get().sort_order); + swaps++; + } + } + } + + iters++; + if (swaps==0) { + iters=0; + break; + } + } + + if (iters>0) { + + shader[i].error=GRAPH_ERROR_CYCLIC; + continue; + } + + Vector<Node*> order; + order.resize(shader[i].node_map.size()); + + for (Map<int,Node>::Element *E=shader[i].node_map.front();E;E=E->next()) { + + order[E->get().sort_order]=&E->get(); + } + + //generate code for the ordered graph + bool failed=false; + + if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) { + code[i]+="vec3 DIFFUSE_OUT=vec3(0,0,0);\n"; + code[i]+="float ALPHA_OUT=0;\n"; + } + + + Map<String,String> inputs_xlate; + Map<String,String> input_names_xlate; + Set<String> inputs_used; + + for(int j=0;j<order.size();j++) { + + Node *n=order[j]; + if (n->type==NODE_INPUT) { + + const InOutParamInfo* iop = &inout_param_info[0]; + int idx=0; + while(iop->name) { + if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_IN==iop->dir) { + + const char *typestr[4]={"float","vec3","mat4","texture"}; + + String vname=("nd"+itos(n->id)+"sl"+itos(idx)); + inputs_xlate[vname]=String(typestr[iop->slot_type])+" "+vname+"="+iop->variable+";\n"; + input_names_xlate[vname]=iop->variable; + idx++; + } + iop++; + } + + } else if (n->type==NODE_OUTPUT) { + + + bool use_alpha=false; + const InOutParamInfo* iop = &inout_param_info[0]; + int idx=0; + while(iop->name) { + if (get_mode()==iop->shader_mode && i==iop->shader_type && SLOT_OUT==iop->dir) { + + if (n->connections.has(idx)) { + String iname=("nd"+itos(n->connections[idx].id)+"sl"+itos(n->connections[idx].slot)); + if (node_get_type(ShaderType(i),n->connections[idx].id)==NODE_INPUT) + inputs_used.insert(iname); + code[i]+=String(iop->variable)+"="+iname+String(iop->postfix)+";\n"; + if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL && String(iop->name)=="DiffuseAlpha") + use_alpha=true; + } + idx++; + } + iop++; + } + + if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) { + + if (use_alpha) { + code[i]+="DIFFUSE_ALPHA=vec4(DIFFUSE_OUT,ALPHA_OUT);\n"; + } else { + code[i]+="DIFFUSE=DIFFUSE_OUT;\n"; + } + } + + } else { + Vector<String> inputs; + int max = get_node_input_slot_count(get_mode(),ShaderType(i),n->type); + for(int k=0;k<max;k++) { + if (!n->connections.has(k)) { + shader[i].error=GRAPH_ERROR_MISSING_CONNECTIONS; + failed=true; + break; + } + String iname="nd"+itos(n->connections[k].id)+"sl"+itos(n->connections[k].slot); + inputs.push_back(iname); + if (node_get_type(ShaderType(i),n->connections[k].id)==NODE_INPUT) { + inputs_used.insert(iname); + } + + } + + if (failed) + break; + + if (n->type==NODE_TEXTURE_INPUT || n->type==NODE_CUBEMAP_INPUT) { + + set_default_texture_param(n->param1,n->param2); + } + _add_node_code(ShaderType(i),n,inputs,code[i]); + } + + } + + if (failed) + continue; + + + for(Set<String>::Element *E=inputs_used.front();E;E=E->next()) { + + ERR_CONTINUE( !inputs_xlate.has(E->get())); + code[i]=inputs_xlate[E->get()]+code[i]; + String name=input_names_xlate[E->get()]; + + if (i==SHADER_TYPE_VERTEX && get_mode()==MODE_MATERIAL) { + if (name==("SRC_COLOR")) + code[i]="vec3 SRC_COLOR=COLOR.rgb;\n"+code[i]; + if (name==("SRC_ALPHA")) + code[i]="float SRC_ALPHA=COLOR.a;\n"+code[i]; + if (name==("SRC_UV")) + code[i]="vec3 SRC_UV=vec3(UV,0);\n"+code[i]; + if (name==("SRC_UV2")) + code[i]="float SRC_UV2=vec3(UV2,0);\n"+code[i]; + } else if (i==SHADER_TYPE_FRAGMENT && get_mode()==MODE_MATERIAL) { + if (name==("IN_NORMAL")) + code[i]="vec3 IN_NORMAL=NORMAL;\n"+code[i]; + } + + } + + + + shader[i].error=GRAPH_OK; + + } + + bool all_ok=true; + for(int i=0;i<3;i++) { + if (shader[i].error!=GRAPH_OK) + all_ok=false; } - ERR_FAIL_V(false); -} -bool ShaderGraph::shader_is_output_vector(NodeType p_type,int p_input) { - - switch(p_type) { - - case NODE_IN: return false; - case NODE_OUT: return false ; - case NODE_CONSTANT: return false; - case NODE_PARAMETER: return false; - case NODE_ADD: return false; - case NODE_SUB: return false; - case NODE_MUL: return false; - case NODE_DIV: return false; - case NODE_MOD: return false; - case NODE_SIN: return false; - case NODE_COS: return false; - case NODE_TAN: return false; - case NODE_ARCSIN: return false; - case NODE_ARCCOS: return false; - case NODE_ARCTAN: return false; - case NODE_POW: return false; - case NODE_LOG: return false; - case NODE_MAX: return false; - case NODE_MIN: return false; - case NODE_COMPARE: return false; - case NODE_TEXTURE: return false; - case NODE_TIME: return false; - case NODE_NOISE: return false; - case NODE_PASS: return false; - case NODE_VEC_IN: return true; - case NODE_VEC_OUT: return false; - case NODE_VEC_CONSTANT: return true; - case NODE_VEC_PARAMETER: return true; - case NODE_VEC_ADD: return true; - case NODE_VEC_SUB: return true; - case NODE_VEC_MUL: return true; - case NODE_VEC_DIV: return true; - case NODE_VEC_MOD: return true; - case NODE_VEC_CROSS: return true; - case NODE_VEC_DOT: return false; - case NODE_VEC_POW: return true; - case NODE_VEC_NORMALIZE: return true; - case NODE_VEC_INTERPOLATE: return true; - case NODE_VEC_SCREEN_TO_UV: return true; - case NODE_VEC_TRANSFORM3: return true; - case NODE_VEC_TRANSFORM4: return true; - case NODE_VEC_COMPARE: return true; - case NODE_VEC_TEXTURE_2D: return (p_input==0)?true:false; - case NODE_VEC_TEXTURE_CUBE: return (p_input==0)?true:false; - case NODE_VEC_NOISE: return true; - case NODE_VEC_0: return false; - case NODE_VEC_1: return false; - case NODE_VEC_2: return false; - case NODE_VEC_BUILD: return true; - case NODE_VEC_PASS: return true; - case NODE_COLOR_CONSTANT: return (p_input==0)?true:false; - case NODE_COLOR_PARAMETER: return (p_input==0)?true:false; - case NODE_TEXTURE_PARAMETER: return (p_input==0)?true:false; - case NODE_TEXTURE_2D_PARAMETER: return (p_input==0)?true:false; - case NODE_TEXTURE_CUBE_PARAMETER: return (p_input==0)?true:false; - case NODE_TRANSFORM_CONSTANT: return true; - case NODE_TRANSFORM_PARAMETER: return true; - case NODE_LABEL: return false; - - default: {} + if (all_ok) { + set_code(code[0],code[1],code[2]); } + //do shader here - ERR_FAIL_V(""); + _pending_update_shader=false; + emit_signal(SceneStringNames::get_singleton()->updated); } -#endif -#endif +void ShaderGraph::_add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code) { + + + const char *typestr[4]={"float","vec3","mat4","texture"}; +#define OUTNAME(id,slot) (String(typestr[get_node_output_slot_type(get_mode(),p_type,p_node->type,slot)])+" "+("nd"+itos(id)+"sl"+itos(slot))) +#define OUTVAR(id,slot) ("nd"+itos(id)+"sl"+itos(slot)) + + switch(p_node->type) { + + case NODE_INPUT: { + + + }break; + case NODE_SCALAR_CONST: { + + double scalar = p_node->param1; + code+=OUTNAME(p_node->id,0)+"="+rtos(scalar)+";\n"; + }break; + case NODE_VEC_CONST: { + Vector3 vec = p_node->param1; + code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(vec.x)+","+rtos(vec.y)+","+rtos(vec.z)+");\n"; + }break; + case NODE_RGB_CONST: { + Color col = p_node->param1; + code+=OUTNAME(p_node->id,0)+"=vec3("+rtos(col.r)+","+rtos(col.g)+","+rtos(col.b)+");\n"; + code+=OUTNAME(p_node->id,1)+"="+rtos(col.a)+";\n"; + }break; + case NODE_XFORM_CONST: { + + Transform xf = p_node->param1; + code+=OUTNAME(p_node->id,0)+"=mat4(\n"; + code+="\tvec4(vec3("+rtos(xf.basis.get_axis(0).x)+","+rtos(xf.basis.get_axis(0).y)+","+rtos(xf.basis.get_axis(0).z)+"),0),\n"; + code+="\tvec4(vec3("+rtos(xf.basis.get_axis(1).x)+","+rtos(xf.basis.get_axis(1).y)+","+rtos(xf.basis.get_axis(1).z)+"),0),\n"; + code+="\tvec4(vec3("+rtos(xf.basis.get_axis(2).x)+","+rtos(xf.basis.get_axis(2).y)+","+rtos(xf.basis.get_axis(2).z)+"),0),\n"; + code+="\tvec4(vec3("+rtos(xf.origin.x)+","+rtos(xf.origin.y)+","+rtos(xf.origin.z)+"),1)\n"; + code+=");"; + + }break; + case NODE_TIME: { + code+=OUTNAME(p_node->id,0)+"=TIME;\n"; + }break; + case NODE_SCREEN_TEX: { + code+=OUTNAME(p_node->id,0)+"=texscreen("+p_inputs[0]+");\n"; + }break; + case NODE_SCALAR_OP: { + int op = p_node->param1; + String optxt; + switch(op) { + + case SCALAR_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break; + case SCALAR_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break; + case SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break; + case SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break; + case SCALAR_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break; + case SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break; + case SCALAR_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break; + case SCALAR_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break; + case SCALAR_OP_ATAN2: optxt = "atan2("+p_inputs[0]+","+p_inputs[1]+");"; break; + + } + code+=OUTNAME(p_node->id,0)+"="+optxt+"\n";; + + }break; + case NODE_VEC_OP: { + int op = p_node->param1; + String optxt; + switch(op) { + case VEC_OP_ADD: optxt = p_inputs[0]+"+"+p_inputs[1]+";"; break; + case VEC_OP_SUB: optxt = p_inputs[0]+"-"+p_inputs[1]+";"; break; + case VEC_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break; + case VEC_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break; + case VEC_OP_MOD: optxt = "mod("+p_inputs[0]+","+p_inputs[1]+");"; break; + case VEC_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break; + case VEC_OP_MAX: optxt = "max("+p_inputs[0]+","+p_inputs[1]+");"; break; + case VEC_OP_MIN: optxt = "min("+p_inputs[0]+","+p_inputs[1]+");"; break; + case VEC_OP_CROSS: optxt = "cross("+p_inputs[0]+","+p_inputs[1]+");"; break; + } + code+=OUTNAME(p_node->id,0)+"="+optxt+"\n"; + + }break; + case NODE_VEC_SCALAR_OP: { + int op = p_node->param1; + String optxt; + switch(op) { + case VEC_SCALAR_OP_MUL: optxt = p_inputs[0]+"*"+p_inputs[1]+";"; break; + case VEC_SCALAR_OP_DIV: optxt = p_inputs[0]+"/"+p_inputs[1]+";"; break; + case VEC_SCALAR_OP_POW: optxt = "pow("+p_inputs[0]+","+p_inputs[1]+");"; break; + } + code+=OUTNAME(p_node->id,0)+"="+optxt+"\n"; + + }break; + case NODE_RGB_OP: { + + int op = p_node->param1; + static const char*axisn[3]={"x","y","z"}; + switch(op) { + case RGB_OP_SCREEN: { + + code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")*(vec3(1.0)-"+p_inputs[1]+");\n"; + } break; + case RGB_OP_DIFFERENCE: { + + code += OUTNAME(p_node->id,0)+"=abs("+p_inputs[0]+"-"+p_inputs[1]+");\n"; + + } break; + case RGB_OP_DARKEN: { + + code += OUTNAME(p_node->id,0)+"=min("+p_inputs[0]+","+p_inputs[1]+");\n"; + } break; + case RGB_OP_LIGHTEN: { + + code += OUTNAME(p_node->id,0)+"=max("+p_inputs[0]+","+p_inputs[1]+");\n"; + + } break; + case RGB_OP_OVERLAY: { + + code += OUTNAME(p_node->id,0)+";\n"; + for(int i=0;i<3;i++) { + code += "{\n"; + code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n"; + code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n"; + code += "\tif (base < 0.5) {\n"; + code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 2.0 * base * blend;\n"; + code += "\t} else {\n"; + code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = 1.0 - 2.0 * (1.0 - blend) * (1.0 - base);\n"; + code += "\t}\n"; + code += "}\n"; + } + + } break; + case RGB_OP_DODGE: { + + code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+")/(vec3(1.0)-"+p_inputs[1]+");\n"; + + } break; + case RGB_OP_BURN: { + + code += OUTNAME(p_node->id,0)+"=vec3(1.0)-(vec3(1.0)-"+p_inputs[0]+")/("+p_inputs[1]+");\n"; + } break; + case RGB_OP_SOFT_LIGHT: { + + code += OUTNAME(p_node->id,0)+";\n"; + for(int i=0;i<3;i++) { + code += "{\n"; + code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n"; + code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n"; + code += "\tif (base < 0.5) {\n"; + code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (blend+0.5));\n"; + code += "\t} else {\n"; + code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-(blend-0.5)));\n"; + code += "\t}\n"; + code += "}\n"; + } + + } break; + case RGB_OP_HARD_LIGHT: { + + code += OUTNAME(p_node->id,0)+";\n"; + for(int i=0;i<3;i++) { + code += "{\n"; + code += "\tfloat base="+p_inputs[0]+"."+axisn[i]+";\n"; + code += "\tfloat blend="+p_inputs[1]+"."+axisn[i]+";\n"; + code += "\tif (base < 0.5) {\n"; + code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (base * (2*blend));\n"; + code += "\t} else {\n"; + code += "\t\t"+OUTVAR(p_node->id,0)+"."+axisn[i]+" = (1 - (1-base) * (1-2*(blend-0.5)));\n"; + code += "\t}\n"; + code += "}\n"; + } + + } break; + } + }break; + case NODE_XFORM_MULT: { + + code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+"*"+p_inputs[1]+";\n"; + + }break; + case NODE_XFORM_VEC_MULT: { + + bool no_translation = p_node->param1; + if (no_translation) { + code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",0)).xyz;\n"; + } else { + code += OUTNAME(p_node->id,0)+"=("+p_inputs[0]+"*vec4("+p_inputs[1]+",1)).xyz;\n"; + } + + }break; + case NODE_XFORM_VEC_INV_MULT: { + bool no_translation = p_node->param1; + if (no_translation) { + code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",0)).xyz;\n"; + } else { + code += OUTNAME(p_node->id,0)+"=("+p_inputs[1]+"*vec4("+p_inputs[0]+",1)).xyz;\n"; + } + }break; + case NODE_SCALAR_FUNC: { + static const char*scalar_func_id[SCALAR_MAX_FUNC]={ + "sin($)", + "cos($)", + "tan($)", + "asin($)", + "acos($)", + "atan($)", + "sinh($)", + "cosh($)", + "tanh($)", + "log($)", + "exp($)", + "sqrt($)", + "abs($)", + "sign($)", + "floor($)", + "round($)", + "ceil($)", + "frac($)", + "min(max($,0),1)", + "-($)", + }; + + int func = p_node->param1; + ERR_FAIL_INDEX(func,SCALAR_MAX_FUNC); + code += OUTNAME(p_node->id,0)+"="+String(scalar_func_id[func]).replace("$",p_inputs[0])+";\n"; + + } break; + case NODE_VEC_FUNC: { + static const char*vec_func_id[VEC_MAX_FUNC]={ + "normalize($)", + "max(min($,vec3(1,1,1)),vec3(0,0,0))", + "-($)", + "1.0/($)", + "", + "", + }; + + + int func = p_node->param1; + ERR_FAIL_INDEX(func,VEC_MAX_FUNC); + if (func==VEC_FUNC_RGB2HSV) { + code += OUTNAME(p_node->id,0)+";\n"; + code+="{\n"; + code+="\tvec3 c = "+p_inputs[0]+";\n"; + code+="\tvec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);\n"; + code+="\tvec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));\n"; + code+="\tvec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));\n"; + code+="\tfloat d = q.x - min(q.w, q.y);\n"; + code+="\tfloat e = 1.0e-10;\n"; + code+="\t"+OUTVAR(p_node->id,0)+"=vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);\n"; + code+="}\n"; + } else if (func==VEC_FUNC_HSV2RGB) { + code += OUTNAME(p_node->id,0)+";\n";; + code+="{\n"; + code+="\tvec3 c = "+p_inputs[0]+";\n"; + code+="\tvec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);\n"; + code+="\tvec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);\n"; + code+="\t"+OUTVAR(p_node->id,0)+"=c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);\n"; + code+="}\n"; + + } else { + code += OUTNAME(p_node->id,0)+"="+String(vec_func_id[func]).replace("$",p_inputs[0])+";\n"; + } + }break; + case NODE_VEC_LEN: { + + code += OUTNAME(p_node->id,0)+"=length("+p_inputs[1]+");\n"; + + }break; + case NODE_DOT_PROD: { + code += OUTNAME(p_node->id,0)+"=dot("+p_inputs[1]+","+p_inputs[0]+");\n"; + + }break; + case NODE_VEC_TO_SCALAR: { + code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n"; + code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n"; + code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n"; + + }break; + case NODE_SCALAR_TO_VEC: { + code += OUTNAME(p_node->id,0)+"=vec3("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+""+");\n"; + + }break; + case NODE_VEC_TO_XFORM: { + code += OUTNAME(p_node->id,0)+"=xform("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+","+","+p_inputs[3]+");\n"; + + }break; + case NODE_XFORM_TO_VEC: { + code += OUTNAME(p_node->id,0)+"="+p_inputs[0]+".x;\n"; + code += OUTNAME(p_node->id,1)+"="+p_inputs[0]+".y;\n"; + code += OUTNAME(p_node->id,2)+"="+p_inputs[0]+".z;\n"; + code += OUTNAME(p_node->id,3)+"="+p_inputs[0]+".o;\n"; + }break; + case NODE_SCALAR_INTERP: { + + code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n"; + + }break; + case NODE_VEC_INTERP: { + code += OUTNAME(p_node->id,0)+"=mix("+p_inputs[0]+","+p_inputs[1]+","+p_inputs[2]+");\n"; + + }break; + case NODE_SCALAR_INPUT: { + String name = p_node->param1; + float dv=p_node->param2; + code +="uniform float "+name+"="+rtos(dv)+";\n"; + code += OUTNAME(p_node->id,0)+"="+name+";\n"; + }break; + case NODE_VEC_INPUT: { + + String name = p_node->param1; + Vector3 dv=p_node->param2; + code +="uniform float "+name+"=vec3("+rtos(dv.x)+","+rtos(dv.y)+","+rtos(dv.z)+");\n"; + code += OUTNAME(p_node->id,0)+"="+name+";\n"; + }break; + case NODE_RGB_INPUT: { + + String name = p_node->param1; + Color dv= p_node->param2; + + code +="uniform color "+name+"=vec4("+rtos(dv.r)+","+rtos(dv.g)+","+rtos(dv.g)+","+rtos(dv.a)+");\n"; + code += OUTNAME(p_node->id,0)+"="+name+".rgb;\n"; + + }break; + case NODE_XFORM_INPUT: { + + String name = p_node->param1; + Transform dv= p_node->param2; + + code +="uniform mat4 "+name+"=mat4(\n"; + code+="\tvec4(vec3("+rtos(dv.basis.get_axis(0).x)+","+rtos(dv.basis.get_axis(0).y)+","+rtos(dv.basis.get_axis(0).z)+"),0),\n"; + code+="\tvec4(vec3("+rtos(dv.basis.get_axis(1).x)+","+rtos(dv.basis.get_axis(1).y)+","+rtos(dv.basis.get_axis(1).z)+"),0),\n"; + code+="\tvec4(vec3("+rtos(dv.basis.get_axis(2).x)+","+rtos(dv.basis.get_axis(2).y)+","+rtos(dv.basis.get_axis(2).z)+"),0),\n"; + code+="\tvec4(vec3("+rtos(dv.origin.x)+","+rtos(dv.origin.y)+","+rtos(dv.origin.z)+"),1)\n"; + code+=");"; + + code += OUTNAME(p_node->id,0)+"="+name+";\n"; + + }break; + case NODE_TEXTURE_INPUT: { + String name = p_node->param1; + String rname="rt_read_tex"+itos(p_node->id); + code +="uniform texture "+name+";"; + code +="vec4 "+rname+"=tex("+name+","+p_inputs[0]+".xy);\n"; + code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n"; + code += OUTNAME(p_node->id,1)+"="+rname+".a;\n"; + + }break; + case NODE_CUBEMAP_INPUT: { + + String name = p_node->param1; + code +="uniform cubemap "+name+";"; + String rname="rt_read_tex"+itos(p_node->id); + code +="vec4 "+rname+"=texcube("+name+","+p_inputs[0]+".xy);\n"; + code += OUTNAME(p_node->id,0)+"="+rname+".rgb;\n"; + code += OUTNAME(p_node->id,1)+"="+rname+".a;\n"; + }break; + case NODE_OUTPUT: { + + + }break; + case NODE_COMMENT: { + + }break; + case NODE_TYPE_MAX: { + + } + } +} diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h index e20e010c6b..55d09b4c38 100644 --- a/scene/resources/shader_graph.h +++ b/scene/resources/shader_graph.h @@ -29,87 +29,54 @@ #ifndef SHADER_GRAPH_H #define SHADER_GRAPH_H -#if 0 + #include "map.h" #include "scene/resources/shader.h" -class ShaderGraph : public Resource { +class ShaderGraph : public Shader { - OBJ_TYPE( ShaderGraph, Resource ); + OBJ_TYPE( ShaderGraph, Shader ); RES_BASE_EXTENSION("sgp"); public: enum NodeType { - NODE_IN, ///< param 0: name - NODE_OUT, ///< param 0: name - NODE_CONSTANT, ///< param 0: value - NODE_PARAMETER, ///< param 0: name - NODE_ADD, - NODE_SUB, - NODE_MUL, - NODE_DIV, - NODE_MOD, - NODE_SIN, - NODE_COS, - NODE_TAN, - NODE_ARCSIN, - NODE_ARCCOS, - NODE_ARCTAN, - NODE_POW, - NODE_LOG, - NODE_MAX, - NODE_MIN, - NODE_COMPARE, - NODE_TEXTURE, ///< param 0: texture - NODE_TIME, ///< param 0: interval length - NODE_NOISE, - NODE_PASS, - NODE_VEC_IN, ///< param 0: name - NODE_VEC_OUT, ///< param 0: name - NODE_VEC_CONSTANT, ///< param 0: value - NODE_VEC_PARAMETER, ///< param 0: name - NODE_VEC_ADD, - NODE_VEC_SUB, - NODE_VEC_MUL, - NODE_VEC_DIV, - NODE_VEC_MOD, - NODE_VEC_CROSS, - NODE_VEC_DOT, - NODE_VEC_POW, - NODE_VEC_NORMALIZE, - NODE_VEC_INTERPOLATE, - NODE_VEC_SCREEN_TO_UV, - NODE_VEC_TRANSFORM3, - NODE_VEC_TRANSFORM4, - NODE_VEC_COMPARE, - NODE_VEC_TEXTURE_2D, - NODE_VEC_TEXTURE_CUBE, - NODE_VEC_NOISE, - NODE_VEC_0, - NODE_VEC_1, - NODE_VEC_2, - NODE_VEC_BUILD, - NODE_VEC_PASS, - NODE_COLOR_CONSTANT, - NODE_COLOR_PARAMETER, - NODE_TEXTURE_PARAMETER, - NODE_TEXTURE_2D_PARAMETER, - NODE_TEXTURE_CUBE_PARAMETER, - NODE_TRANSFORM_CONSTANT, - NODE_TRANSFORM_PARAMETER, - NODE_LABEL, + NODE_INPUT, // all inputs (shader type dependent) + NODE_SCALAR_CONST, //scalar constant + NODE_VEC_CONST, //vec3 constant + NODE_RGB_CONST, //rgb constant (shows a color picker instead) + NODE_XFORM_CONST, // 4x4 matrix constant + NODE_TIME, // time in seconds + NODE_SCREEN_TEX, // screen texture sampler (takes UV) (only usable in fragment shader) + NODE_SCALAR_OP, // scalar vs scalar op (mul, add, div, etc) + NODE_VEC_OP, // vec3 vs vec3 op (mul,ad,div,crossprod,etc) + NODE_VEC_SCALAR_OP, // vec3 vs scalar op (mul, add, div, etc) + NODE_RGB_OP, // vec3 vs vec3 rgb op (with scalar amount), like brighten, darken, burn, dodge, multiply, etc. + NODE_XFORM_MULT, // mat4 x mat4 + NODE_XFORM_VEC_MULT, // mat4 x vec3 mult (with no-translation option) + NODE_XFORM_VEC_INV_MULT, // mat4 x vec3 inverse mult (with no-translation option) + NODE_SCALAR_FUNC, // scalar function (sin, cos, etc) + NODE_VEC_FUNC, // vector function (normalize, negate, reciprocal, rgb2hsv, hsv2rgb, etc, etc) + NODE_VEC_LEN, // vec3 length + NODE_DOT_PROD, // vec3 . vec3 (dot product -> scalar output) + NODE_VEC_TO_SCALAR, // 1 vec3 input, 3 scalar outputs + NODE_SCALAR_TO_VEC, // 3 scalar input, 1 vec3 output + NODE_XFORM_TO_VEC, // 3 vec input, 1 xform output + NODE_VEC_TO_XFORM, // 3 vec input, 1 xform output + NODE_SCALAR_INTERP, // scalar interpolation (with optional curve) + NODE_VEC_INTERP, // vec3 interpolation (with optional curve) + NODE_SCALAR_INPUT, // scalar uniform (assignable in material) + NODE_VEC_INPUT, // vec3 uniform (assignable in material) + NODE_RGB_INPUT, // color uniform (assignable in material) + NODE_XFORM_INPUT, // mat4 uniform (assignable in material) + NODE_TEXTURE_INPUT, // texture input (assignable in material) + NODE_CUBEMAP_INPUT, // cubemap input (assignable in material) + NODE_OUTPUT, // output (shader type dependent) + NODE_COMMENT, // comment NODE_TYPE_MAX }; - enum ShaderType { - SHADER_VERTEX, - SHADER_FRAGMENT, - SHADER_LIGHT - }; - -private: struct Connection { @@ -119,70 +86,292 @@ private: int dst_slot; }; + enum SlotType { + + SLOT_TYPE_SCALAR, + SLOT_TYPE_VEC, + SLOT_TYPE_XFORM, + SLOT_TYPE_TEXTURE, + SLOT_MAX + }; + + enum ShaderType { + SHADER_TYPE_VERTEX, + SHADER_TYPE_FRAGMENT, + SHADER_TYPE_LIGHT, + SHADER_TYPE_MAX + }; + + enum SlotDir { + SLOT_IN, + SLOT_OUT + }; + + enum GraphError { + GRAPH_OK, + GRAPH_ERROR_CYCLIC, + GRAPH_ERROR_MISSING_CONNECTIONS + }; + +private: + + String _find_unique_name(const String& p_base); + + struct SourceSlot { + + int id; + int slot; + bool operator==(const SourceSlot& p_slot) const { + return id==p_slot.id && slot==p_slot.slot; + } + }; + struct Node { - int16_t x,y; + Vector2 pos; NodeType type; - Variant param; + Variant param1; + Variant param2; int id; mutable int order; // used for sorting - mutable bool out_valid; - mutable bool in_valid; + int sort_order; + Map<int,SourceSlot> connections; + }; struct ShaderData { Map<int,Node> node_map; - List<Connection> connections; + GraphError error; } shader[3]; - uint64_t version; -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(); + struct InOutParamInfo { + Mode shader_mode; + ShaderType shader_type; + const char *name; + const char *variable; + const char *postfix; + SlotType slot_type; + SlotDir dir; + }; + + static const InOutParamInfo inout_param_info[]; + + struct NodeSlotInfo { + + enum { MAX_INS=3, MAX_OUTS=3 }; + NodeType type; + const SlotType ins[MAX_INS]; + const SlotType outs[MAX_OUTS]; + }; - Array _get_connections_helper() const; + static const NodeSlotInfo node_slot_info[]; + + bool _pending_update_shader; + void _update_shader(); + void _request_update(); + + void _add_node_code(ShaderType p_type,Node *p_node,const Vector<String>& p_inputs,String& code); + + Array _get_node_list(ShaderType p_type) const; + Array _get_connections(ShaderType p_type) const; + + void _set_data(const Dictionary& p_data); + Dictionary _get_data() const; +protected: + + static void _bind_methods(); public: - void node_add(ShaderType p_which, NodeType p_type,int p_id); + void node_add(ShaderType p_type, NodeType p_node_type, int p_id); void node_remove(ShaderType p_which,int p_id); - void node_set_param(ShaderType p_which, int p_id, const Variant& p_value); void node_set_pos(ShaderType p_which,int p_id,const Point2& p_pos); - void node_change_type(ShaderType p_which,int p_id, NodeType p_type); Point2 node_get_pos(ShaderType p_which,int p_id) const; void get_node_list(ShaderType p_which,List<int> *p_node_list) const; NodeType node_get_type(ShaderType p_which,int p_id) const; - Variant node_get_param(ShaderType p_which,int p_id) const; - Error connect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); - bool is_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const; - void disconnect(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); + void scalar_const_node_set_value(ShaderType p_which,int p_id,float p_value); + float scalar_const_node_get_value(ShaderType p_which,int p_id) const; - void get_connections(ShaderType p_which,List<Connection> *p_connections) const; + void vec_const_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value); + Vector3 vec_const_node_get_value(ShaderType p_which,int p_id) const; - void clear(); + void rgb_const_node_set_value(ShaderType p_which,int p_id,const Color& p_value); + Color rgb_const_node_get_value(ShaderType p_which,int p_id) const; - uint64_t get_version() const { return version; } + void xform_const_node_set_value(ShaderType p_which,int p_id,const Transform& p_value); + Transform xform_const_node_get_value(ShaderType p_which,int p_id) const; - static void get_default_input_nodes(Mode p_type,List<PropertyInfo> *p_inputs); - static void get_default_output_nodes(Mode p_type,List<PropertyInfo> *p_outputs); + void texture_node_set_filter_size(ShaderType p_which,int p_id,int p_size); + int texture_node_get_filter_size(ShaderType p_which,int p_id) const; - static PropertyInfo node_get_type_info(NodeType p_type); - static int get_input_count(NodeType p_type); - static int get_output_count(NodeType p_type); - static String get_input_name(NodeType p_type,int p_input); - static String get_output_name(NodeType p_type,int p_output); - static bool is_input_vector(NodeType p_type,int p_input); - static bool is_output_vector(NodeType p_type,int p_input); + void texture_node_set_filter_strength(ShaderType p_which,float p_id,float p_strength); + float texture_node_get_filter_strength(ShaderType p_which,float p_id) const; + enum ScalarOp { + SCALAR_OP_ADD, + SCALAR_OP_SUB, + SCALAR_OP_MUL, + SCALAR_OP_DIV, + SCALAR_OP_MOD, + SCALAR_OP_POW, + SCALAR_OP_MAX, + SCALAR_OP_MIN, + SCALAR_OP_ATAN2, + SCALAR_MAX_OP + }; + + void scalar_op_node_set_op(ShaderType p_which,float p_id,ScalarOp p_op); + ScalarOp scalar_op_node_get_op(ShaderType p_which,float p_id) const; + + enum VecOp { + VEC_OP_ADD, + VEC_OP_SUB, + VEC_OP_MUL, + VEC_OP_DIV, + VEC_OP_MOD, + VEC_OP_POW, + VEC_OP_MAX, + VEC_OP_MIN, + VEC_OP_CROSS, + VEC_MAX_OP + }; - ShaderGraph(); + void vec_op_node_set_op(ShaderType p_which,float p_id,VecOp p_op); + VecOp vec_op_node_get_op(ShaderType p_which,float p_id) const; + + enum VecScalarOp { + VEC_SCALAR_OP_MUL, + VEC_SCALAR_OP_DIV, + VEC_SCALAR_OP_POW, + VEC_SCALAR_MAX_OP + }; + + void vec_scalar_op_node_set_op(ShaderType p_which,float p_id,VecScalarOp p_op); + VecScalarOp vec_scalar_op_node_get_op(ShaderType p_which,float p_id) const; + + enum RGBOp { + RGB_OP_SCREEN, + RGB_OP_DIFFERENCE, + RGB_OP_DARKEN, + RGB_OP_LIGHTEN, + RGB_OP_OVERLAY, + RGB_OP_DODGE, + RGB_OP_BURN, + RGB_OP_SOFT_LIGHT, + RGB_OP_HARD_LIGHT, + RGB_MAX_OP + }; + + void rgb_op_node_set_op(ShaderType p_which,float p_id,RGBOp p_op); + RGBOp rgb_op_node_get_op(ShaderType p_which,float p_id) const; + + void xform_vec_mult_node_set_no_translation(ShaderType p_which,int p_id,bool p_no_translation); + bool xform_vec_mult_node_get_no_translation(ShaderType p_which,int p_id) const; + + enum ScalarFunc { + SCALAR_FUNC_SIN, + SCALAR_FUNC_COS, + SCALAR_FUNC_TAN, + SCALAR_FUNC_ASIN, + SCALAR_FUNC_ACOS, + SCALAR_FUNC_ATAN, + SCALAR_FUNC_SINH, + SCALAR_FUNC_COSH, + SCALAR_FUNC_TANH, + SCALAR_FUNC_LOG, + SCALAR_FUNC_EXP, + SCALAR_FUNC_SQRT, + SCALAR_FUNC_ABS, + SCALAR_FUNC_SIGN, + SCALAR_FUNC_FLOOR, + SCALAR_FUNC_ROUND, + SCALAR_FUNC_CEIL, + SCALAR_FUNC_FRAC, + SCALAR_FUNC_SATURATE, + SCALAR_FUNC_NEGATE, + SCALAR_MAX_FUNC + }; + + void scalar_func_node_set_function(ShaderType p_which,int p_id,ScalarFunc p_func); + ScalarFunc scalar_func_node_get_function(ShaderType p_which,int p_id) const; + + enum VecFunc { + VEC_FUNC_NORMALIZE, + VEC_FUNC_SATURATE, + VEC_FUNC_NEGATE, + VEC_FUNC_RECIPROCAL, + VEC_FUNC_RGB2HSV, + VEC_FUNC_HSV2RGB, + VEC_MAX_FUNC + }; + + void vec_func_node_set_function(ShaderType p_which,int p_id,VecFunc p_func); + VecFunc vec_func_node_get_function(ShaderType p_which,int p_id) const; + + void input_node_set_name(ShaderType p_which,int p_id,const String& p_name); + String input_node_get_name(ShaderType p_which,int p_id); + + void scalar_input_node_set_value(ShaderType p_which,int p_id,float p_value); + float scalar_input_node_get_value(ShaderType p_which,int p_id) const; + + void vec_input_node_set_value(ShaderType p_which,int p_id,const Vector3& p_value); + Vector3 vec_input_node_get_value(ShaderType p_which,int p_id) const; + + void rgb_input_node_set_value(ShaderType p_which,int p_id,const Color& p_value); + Color rgb_input_node_get_value(ShaderType p_which,int p_id) const; + + void xform_input_node_set_value(ShaderType p_which,int p_id,const Transform& p_value); + Transform xform_input_node_get_value(ShaderType p_which,int p_id) const; + + void texture_input_node_set_value(ShaderType p_which,int p_id,const Ref<Texture>& p_texture); + Ref<Texture> texture_input_node_get_value(ShaderType p_which,int p_id) const; + + void cubemap_input_node_set_value(ShaderType p_which,int p_id,const Ref<CubeMap>& p_cubemap); + Ref<CubeMap> cubemap_input_node_get_value(ShaderType p_which,int p_id) const; + + void comment_node_set_text(ShaderType p_which,int p_id,const String& p_comment); + String comment_node_get_text(ShaderType p_which,int p_id) const; + + Error connect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); + bool is_node_connected(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot) const; + void disconnect_node(ShaderType p_which,int p_src_id,int p_src_slot, int p_dst_id,int p_dst_slot); + + void get_node_connections(ShaderType p_which,List<Connection> *p_connections) const; + + void clear(ShaderType p_which); + + Variant node_get_state(ShaderType p_type, int p_node) const; + void node_set_state(ShaderType p_type, int p_id, const Variant& p_state); + + GraphError get_graph_error(ShaderType p_type) const; + + static int get_type_input_count(NodeType p_type); + static int get_type_output_count(NodeType p_type); + static SlotType get_type_input_type(NodeType p_type,int p_idx); + static SlotType get_type_output_type(NodeType p_type,int p_idx); + static bool is_type_valid(Mode p_mode,ShaderType p_type); + + + struct SlotInfo { + String name; + SlotType type; + SlotDir dir; + }; + + static void get_input_output_node_slot_info(Mode p_mode, ShaderType p_type, List<SlotInfo> *r_slots); + + static int get_node_input_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type); + static int get_node_output_slot_count(Mode p_mode, ShaderType p_shader_type,NodeType p_type); + static SlotType get_node_input_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx); + static SlotType get_node_output_slot_type(Mode p_mode, ShaderType p_shader_type,NodeType p_type,int p_idx); + + + ShaderGraph(Mode p_mode); ~ShaderGraph(); }; @@ -192,6 +381,28 @@ public: VARIANT_ENUM_CAST( ShaderGraph::NodeType ); +VARIANT_ENUM_CAST( ShaderGraph::ShaderType ); +VARIANT_ENUM_CAST( ShaderGraph::SlotType ); +VARIANT_ENUM_CAST( ShaderGraph::ScalarOp ); +VARIANT_ENUM_CAST( ShaderGraph::VecOp ); +VARIANT_ENUM_CAST( ShaderGraph::VecScalarOp ); +VARIANT_ENUM_CAST( ShaderGraph::RGBOp ); +VARIANT_ENUM_CAST( ShaderGraph::ScalarFunc ); +VARIANT_ENUM_CAST( ShaderGraph::VecFunc ); +VARIANT_ENUM_CAST( ShaderGraph::GraphError ); + + +class MaterialShaderGraph : public ShaderGraph { + + OBJ_TYPE( MaterialShaderGraph, ShaderGraph ); + RES_BASE_EXTENSION("sgp"); + +public: + + + MaterialShaderGraph() : ShaderGraph(MODE_MATERIAL) { + + } +}; -#endif #endif // SHADER_GRAPH_H diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp index ca891920da..738b642d43 100644 --- a/scene/resources/shape_2d.cpp +++ b/scene/resources/shape_2d.cpp @@ -109,7 +109,7 @@ void Shape2D::_bind_methods() { ObjectTypeDB::bind_method(_MD("collide","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide); ObjectTypeDB::bind_method(_MD("collide_with_motion","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion); ObjectTypeDB::bind_method(_MD("collide_and_get_contacts:var","local_xform","with_shape:Shape2D","shape_xform"),&Shape2D::collide_and_get_contacts); - ObjectTypeDB::bind_method(_MD("collide_with_motion_and_get_contacts:var","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_and_get_contacts); + ObjectTypeDB::bind_method(_MD("collide_with_motion_and_get_contacts:var","local_xform","local_motion","with_shape:Shape2D","shape_xform","shape_motion"),&Shape2D::collide_with_motion_and_get_contacts); ADD_PROPERTY( PropertyInfo(Variant::REAL,"custom_solver_bias",PROPERTY_HINT_RANGE,"0,1,0.001"),_SCS("set_custom_solver_bias"),_SCS("get_custom_solver_bias")); } diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp index 2856101674..113fd8209d 100644 --- a/scene/resources/surface_tool.cpp +++ b/scene/resources/surface_tool.cpp @@ -105,7 +105,7 @@ void SurfaceTool::add_vertex( const Vector3& p_vertex) { vtx.weights=last_weights; vtx.bones=last_bones; vtx.tangent=last_tangent.normal; - vtx.binormal=last_tangent.normal.cross(last_normal).normalized() * last_tangent.d; + vtx.binormal=last_normal.cross(last_tangent.normal).normalized() * last_tangent.d; vertex_array.push_back(vtx); first=false; format|=Mesh::ARRAY_FORMAT_VERTEX; @@ -299,7 +299,9 @@ Ref<Mesh> SurfaceTool::commit(const Ref<Mesh>& p_existing) { w[idx+0]=v.tangent.x; w[idx+1]=v.tangent.y; w[idx+2]=v.tangent.z; - float d = v.binormal.dot(v.normal.cross(v.tangent)); + + //float d = v.tangent.dot(v.binormal,v.normal); + float d = v.binormal.dot( v.normal.cross(v.tangent)); w[idx+3]=d<0 ? -1 : 1; } @@ -565,6 +567,7 @@ void SurfaceTool::create_from(const Ref<Mesh>& p_existing, int p_surface) { clear(); primitive=p_existing->surface_get_primitive_type(p_surface); _create_list(p_existing,p_surface,&vertex_array,&index_array,format); + material=p_existing->surface_get_material(p_surface); } @@ -611,165 +614,96 @@ void SurfaceTool::append_from(const Ref<Mesh>& p_existing, int p_surface,const T } +//mikktspace callbacks +int SurfaceTool::mikktGetNumFaces(const SMikkTSpaceContext * pContext) { -void SurfaceTool::generate_tangents() { - - ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV)); - ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL)); - - - if (index_array.size()) { - - Vector<List<Vertex>::Element*> vtx; - vtx.resize(vertex_array.size()); - int idx=0; - for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) { - vtx[idx++]=E; - E->get().binormal=Vector3(); - E->get().tangent=Vector3(); - } - - for (List<int>::Element *E=index_array.front();E;) { - - int i[3]; - i[0]=E->get(); - E=E->next(); - ERR_FAIL_COND(!E); - i[1]=E->get(); - E=E->next(); - ERR_FAIL_COND(!E); - i[2]=E->get(); - E=E->next(); - ERR_FAIL_COND(!E); - - - Vector3 v1 = vtx[ i[0] ]->get().vertex; - Vector3 v2 = vtx[ i[1] ]->get().vertex; - Vector3 v3 = vtx[ i[2] ]->get().vertex; - - Vector2 w1 = vtx[ i[0] ]->get().uv; - Vector2 w2 = vtx[ i[1] ]->get().uv; - Vector2 w3 = vtx[ i[2] ]->get().uv; - - - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - float z1 = v2.z - v1.z; - float z2 = v3.z - v1.z; - - float s1 = w2.x - w1.x; - float s2 = w3.x - w1.x; - float t1 = w2.y - w1.y; - float t2 = w3.y - w1.y; - - float r = (s1 * t2 - s2 * t1); - - Vector3 binormal,tangent; - - if (r==0) { - binormal=Vector3(0,0,0); - tangent=Vector3(0,0,0); - } else { - tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, - (t2 * z1 - t1 * z2) * r); - binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, - (s1 * z2 - s2 * z1) * r); - } - - tangent.normalize(); - binormal.normalize(); - Vector3 normal=Plane( v1, v2, v3 ).normal; - - Vector3 tangentp = tangent - normal * normal.dot( tangent ); - Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal)); - - tangentp.normalize(); - binormalp.normalize(); + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + return varr.size()/3; +} +int SurfaceTool::mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace){ + return 3; //always 3 +} +void SurfaceTool::mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert){ - for (int j=0;j<3;j++) { - vtx[ i[j] ]->get().binormal+=binormalp; - vtx[ i[j] ]->get().tangent+=tangentp; + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vector3 v = varr[iFace*3+iVert]->get().vertex; + fvPosOut[0]=v.x; + fvPosOut[1]=v.y; + fvPosOut[2]=v.z; - } - } - for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) { - E->get().binormal.normalize(); - E->get().tangent.normalize(); - } +} +void SurfaceTool::mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert){ - } else { + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vector3 v = varr[iFace*3+iVert]->get().normal; + fvNormOut[0]=v.x; + fvNormOut[1]=v.y; + fvNormOut[2]=v.z; - for (List<Vertex>::Element *E=vertex_array.front();E;) { +} +void SurfaceTool::mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert){ - List< Vertex >::Element *v[3]; - v[0]=E; - v[1]=v[0]->next(); - ERR_FAIL_COND(!v[1]); - v[2]=v[1]->next(); - ERR_FAIL_COND(!v[2]); - E=v[2]->next(); + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vector2 v = varr[iFace*3+iVert]->get().uv; + fvTexcOut[0]=v.x; + fvTexcOut[1]=v.y; + //fvTexcOut[1]=1.0-v.y; - Vector3 v1 = v[0]->get().vertex; - Vector3 v2 = v[1]->get().vertex; - Vector3 v3 = v[2]->get().vertex; +} +void SurfaceTool::mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert){ - Vector2 w1 = v[0]->get().uv; - Vector2 w2 = v[1]->get().uv; - Vector2 w3 = v[2]->get().uv; + Vector<List<Vertex>::Element*> &varr = *((Vector<List<Vertex>::Element*>*)pContext->m_pUserData); + Vertex &vtx = varr[iFace*3+iVert]->get(); + vtx.tangent = Vector3(fvTangent[0],fvTangent[1],fvTangent[2]); + vtx.binormal = vtx.normal.cross(vtx.tangent) * fSign; +} - float x1 = v2.x - v1.x; - float x2 = v3.x - v1.x; - float y1 = v2.y - v1.y; - float y2 = v3.y - v1.y; - float z1 = v2.z - v1.z; - float z2 = v3.z - v1.z; - float s1 = w2.x - w1.x; - float s2 = w3.x - w1.x; - float t1 = w2.y - w1.y; - float t2 = w3.y - w1.y; +void SurfaceTool::generate_tangents() { - float r = (s1 * t2 - s2 * t1); + ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_TEX_UV)); + ERR_FAIL_COND(!(format&Mesh::ARRAY_FORMAT_NORMAL)); - Vector3 binormal,tangent; + bool indexed = index_array.size()>0; + if (indexed) + deindex(); - if (r==0) { - binormal=Vector3(0,0,0); - tangent=Vector3(0,0,0); - } else { - tangent = Vector3((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r, - (t2 * z1 - t1 * z2) * r); - binormal = Vector3((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r, - (s1 * z2 - s2 * z1) * r); - } - tangent.normalize(); - binormal.normalize(); - Vector3 normal=Plane( v1, v2, v3 ).normal; + SMikkTSpaceInterface mkif; + mkif.m_getNormal=mikktGetNormal; + mkif.m_getNumFaces=mikktGetNumFaces; + mkif.m_getNumVerticesOfFace=mikktGetNumVerticesOfFace; + mkif.m_getPosition=mikktGetPosition; + mkif.m_getTexCoord=mikktGetTexCoord; + mkif.m_setTSpaceBasic=mikktSetTSpaceBasic; + mkif.m_setTSpace=NULL; - Vector3 tangentp = tangent - normal * normal.dot( tangent ); - Vector3 binormalp = binormal - normal * (normal.dot(binormal)) - tangent * (tangent.dot(binormal)); + SMikkTSpaceContext msc; + msc.m_pInterface=&mkif; - tangentp.normalize(); - binormalp.normalize(); + Vector<List<Vertex>::Element*> vtx; + vtx.resize(vertex_array.size()); + int idx=0; + for (List<Vertex>::Element *E=vertex_array.front();E;E=E->next()) { + vtx[idx++]=E; + E->get().binormal=Vector3(); + E->get().tangent=Vector3(); + } + msc.m_pUserData=&vtx; + bool res = genTangSpaceDefault(&msc); - for (int j=0;j<3;j++) { - v[j]->get().binormal=binormalp; - v[j]->get().tangent=tangentp; + ERR_FAIL_COND(!res); + format|=Mesh::ARRAY_FORMAT_TANGENT; - } - } - } + if (indexed) + index(); - format|=Mesh::ARRAY_FORMAT_TANGENT; } diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h index fe82d3a4ce..fc5940145b 100644 --- a/scene/resources/surface_tool.h +++ b/scene/resources/surface_tool.h @@ -30,7 +30,7 @@ #define SURFACE_TOOL_H #include "scene/resources/mesh.h" - +#include "mikktspace.h" class SurfaceTool : public Reference { @@ -82,6 +82,14 @@ private: void _create_list(const Ref<Mesh>& p_existing, int p_surface, List<Vertex> *r_vertex, List<int> *r_index,int &lformat); + + //mikktspace callbacks + static int mikktGetNumFaces(const SMikkTSpaceContext * pContext); + static int mikktGetNumVerticesOfFace(const SMikkTSpaceContext * pContext, const int iFace); + static void mikktGetPosition(const SMikkTSpaceContext * pContext, float fvPosOut[], const int iFace, const int iVert); + static void mikktGetNormal(const SMikkTSpaceContext * pContext, float fvNormOut[], const int iFace, const int iVert); + static void mikktGetTexCoord(const SMikkTSpaceContext * pContext, float fvTexcOut[], const int iFace, const int iVert); + static void mikktSetTSpaceBasic(const SMikkTSpaceContext * pContext, const float fvTangent[], const float fSign, const int iFace, const int iVert); protected: static void _bind_methods(); diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 5b31ba1f1b..dae055890b 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -79,6 +79,8 @@ void Texture::_bind_methods() { BIND_CONSTANT( FLAG_FILTER ); BIND_CONSTANT( FLAG_VIDEO_SURFACE ); BIND_CONSTANT( FLAGS_DEFAULT ); + BIND_CONSTANT( FLAG_ANISOTROPIC_FILTER ); + BIND_CONSTANT( FLAG_CONVERT_TO_LINEAR ); } @@ -179,7 +181,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") ); + p_list->push_back( PropertyInfo( Variant::INT, "flags", PROPERTY_HINT_FLAGS,"Mipmaps,Repeat,Filter,Anisotropic,sRGB") ); 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 86ff246498..4bb2f6d979 100644 --- a/scene/resources/texture.h +++ b/scene/resources/texture.h @@ -52,6 +52,8 @@ public: FLAG_MIPMAPS=VisualServer::TEXTURE_FLAG_MIPMAPS, FLAG_REPEAT=VisualServer::TEXTURE_FLAG_REPEAT, FLAG_FILTER=VisualServer::TEXTURE_FLAG_FILTER, + FLAG_ANISOTROPIC_FILTER=VisualServer::TEXTURE_FLAG_ANISOTROPIC_FILTER, + 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, }; diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp index fffe1ad7fa..2bbae37510 100644 --- a/scene/resources/video_stream.cpp +++ b/scene/resources/video_stream.cpp @@ -33,6 +33,7 @@ void VideoStream::_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); }; diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h index eafacce159..18f0cc3d05 100644 --- a/scene/resources/video_stream.h +++ b/scene/resources/video_stream.h @@ -30,7 +30,7 @@ #define VIDEO_STREAM_H #include "audio_stream_resampled.h" - +#include "scene/resources/texture.h" class VideoStream : public Resource { @@ -59,9 +59,11 @@ public: virtual void seek_pos(float p_time)=0; virtual int get_pending_frame_count() const=0; - virtual Image pop_frame()=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; VideoStream(); diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp index aee7ddde00..0dd6a3d5e7 100644 --- a/scene/resources/world_2d.cpp +++ b/scene/resources/world_2d.cpp @@ -364,12 +364,12 @@ World2D::World2D() { Physics2DServer::get_singleton()->space_set_active(space,true); Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY,GLOBAL_DEF("physics_2d/default_gravity",98)); Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_GRAVITY_VECTOR,GLOBAL_DEF("physics_2d/default_gravity_vector",Vector2(0,1))); - Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_DENSITY,GLOBAL_DEF("physics_2d/default_density",0.1)); + Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_LINEAR_DAMP,GLOBAL_DEF("physics_2d/default_density",0.1)); + Physics2DServer::get_singleton()->area_set_param(space,Physics2DServer::AREA_PARAM_ANGULAR_DAMP,GLOBAL_DEF("physics_2d/default_density",1)); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_RECYCLE_RADIUS,1.0); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONTACT_MAX_SEPARATION,1.5); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_MAX_ALLOWED_PENETRATION,0.3); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_LINEAR_VELOCITY_SLEEP_TRESHOLD,2); - Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO,20); Physics2DServer::get_singleton()->space_set_param(space,Physics2DServer::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS,0.2); indexer = memnew( SpatialIndexer2D ); diff --git a/scene/scene_binds.cpp b/scene/scene_binds.cpp deleted file mode 100644 index 5c6a02611f..0000000000 --- a/scene/scene_binds.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/*************************************************************************/ -/* scene_binds.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#include "scene_binds.h" - - -#ifdef OLD_SCENE_FORMAT_ENABLED -void SceneIO::_bind_methods() { - - ObjectTypeDB::bind_method(_MD("load:Node","path"),&SceneIO::load); - ObjectTypeDB::bind_method(_MD("save","path","scene:Node","flags","optimizer:OptimizedSaver","scene"),&SceneIO::save,DEFVAL(0),DEFVAL(Ref<OptimizedSaver>())); - ObjectTypeDB::bind_method(_MD("load_interactive:SceneInteractiveLoader","path"),&SceneIO::load_interactive); -} - -Node* SceneIO::load(const String& p_scene) { - - return SceneLoader::load(p_scene); -} - -Error SceneIO::save(const String& p_path, Node *p_scene,int p_flags,const Ref<OptimizedSaver> &p_optimizer) { - - return SceneSaver::save(p_path,p_scene,p_flags,p_optimizer); -} - -Ref<SceneInteractiveLoader> SceneIO::load_interactive(const String& p_scene) { - - return SceneLoader::load_interactive(p_scene); -} - -#endif diff --git a/scene/scene_binds.h b/scene/scene_binds.h deleted file mode 100644 index 29e4b9ab60..0000000000 --- a/scene/scene_binds.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************/ -/* scene_binds.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* http://www.godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ -#ifndef SCENE_BINDS_H -#define SCENE_BINDS_H - -#include "scene/io/scene_loader.h" -#include "scene/io/scene_saver.h" - -#ifdef OLD_SCENE_FORMAT_ENABLED - -class SceneIO : public Object { - - OBJ_TYPE( SceneIO, Object ); -protected: - - static void _bind_methods(); -public: - - enum SaveFlags { - - SAVE_FLAG_RELATIVE_PATHS=SceneSaver::FLAG_RELATIVE_PATHS, - SAVE_FLAG_BUNDLE_RESOURCES=SceneSaver::FLAG_BUNDLE_RESOURCES, - SAVE_FLAG_BUNDLE_INSTANCED_SCENES=SceneSaver::FLAG_BUNDLE_INSTANCED_SCENES, - SAVE_FLAG_OMIT_EDITOR_PROPERTIES=SceneSaver::FLAG_OMIT_EDITOR_PROPERTIES, - SAVE_FLAG_SAVE_BIG_ENDIAN=SceneSaver::FLAG_SAVE_BIG_ENDIAN - }; - - Node* load(const String& p_scene); - Error save(const String& p_path, Node *p_scene,int p_flags=0,const Ref<OptimizedSaver> &p_optimizer=Ref<OptimizedSaver>()); - Ref<SceneInteractiveLoader> load_interactive(const String& p_scene); - - SceneIO() {} -}; - -#endif -#endif // SCENE_BINDS_H diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp index 1d99eb6d1f..af5e6d4165 100644 --- a/scene/scene_string_names.cpp +++ b/scene/scene_string_names.cpp @@ -41,8 +41,8 @@ SceneStringNames::SceneStringNames() { visibility_changed=StaticCString::create("visibility_changed"); input_event=StaticCString::create("input_event"); shader_shader=StaticCString::create("shader/shader"); - enter_scene=StaticCString::create("enter_scene"); - exit_scene=StaticCString::create("exit_scene"); + enter_tree=StaticCString::create("enter_tree"); + exit_tree=StaticCString::create("exit_tree"); item_rect_changed=StaticCString::create("item_rect_changed"); size_flags_changed=StaticCString::create("size_flags_changed"); minimum_size_changed=StaticCString::create("minimum_size_changed"); @@ -67,6 +67,7 @@ SceneStringNames::SceneStringNames() { idle=StaticCString::create("idle"); iteration=StaticCString::create("iteration"); update=StaticCString::create("update"); + updated=StaticCString::create("updated"); _get_gizmo_geometry=StaticCString::create("_get_gizmo_geometry"); _can_gizmo_scale=StaticCString::create("_can_gizmo_scale"); @@ -74,8 +75,8 @@ SceneStringNames::SceneStringNames() { _fixed_process=StaticCString::create("_fixed_process"); _process=StaticCString::create("_process"); - _enter_scene=StaticCString::create("_enter_scene"); - _exit_scene=StaticCString::create("_exit_scene"); + _enter_tree=StaticCString::create("_enter_tree"); + _exit_tree=StaticCString::create("_exit_tree"); _enter_world=StaticCString::create("_enter_world"); _exit_world=StaticCString::create("_exit_world"); _ready=StaticCString::create("_ready"); @@ -98,8 +99,8 @@ SceneStringNames::SceneStringNames() { enter_camera=StaticCString::create("enter_camera"); exit_camera=StaticCString::create("exit_camera"); - _body_enter_scene = StaticCString::create("_body_enter_scene"); - _body_exit_scene = StaticCString::create("_body_exit_scene"); + _body_enter_tree = StaticCString::create("_body_enter_tree"); + _body_exit_tree = StaticCString::create("_body_exit_tree"); _input_event=StaticCString::create("_input_event"); @@ -147,4 +148,9 @@ SceneStringNames::SceneStringNames() { _mouse_enter=StaticCString::create("_mouse_enter"); _mouse_exit=StaticCString::create("_mouse_exit"); + _pressed=StaticCString::create("_pressed"); + _toggled=StaticCString::create("_toggled"); + + frame_changed=StaticCString::create("frame_changed"); + } diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h index dd4f8789c2..14e5e83b8d 100644 --- a/scene/scene_string_names.h +++ b/scene/scene_string_names.h @@ -56,13 +56,14 @@ public: StringName _input_event; StringName item_rect_changed; StringName shader_shader; - StringName enter_scene; - StringName exit_scene; + StringName enter_tree; + StringName exit_tree; StringName size_flags_changed; StringName minimum_size_changed; StringName idle; StringName iteration; StringName update; + StringName updated; StringName line_separation; @@ -89,12 +90,15 @@ public: StringName _process; StringName _enter_world; StringName _exit_world; - StringName _enter_scene; - StringName _exit_scene; + StringName _enter_tree; + StringName _exit_tree; StringName _draw; StringName _input; StringName _ready; + StringName _pressed; + StringName _toggled; + StringName _update_scroll; StringName _update_xform; @@ -116,8 +120,8 @@ public: StringName enter_camera; StringName exit_camera; - StringName _body_enter_scene; - StringName _body_exit_scene; + StringName _body_enter_tree; + StringName _body_exit_tree; StringName changed; StringName _shader_changed; @@ -155,6 +159,7 @@ public: StringName _mouse_enter; StringName _mouse_exit; + StringName frame_changed; }; |