summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite.cpp7
-rw-r--r--scene/2d/area_2d.cpp112
-rw-r--r--scene/2d/area_2d.h19
-rw-r--r--scene/2d/camera_2d.cpp16
-rw-r--r--scene/2d/canvas_item.cpp149
-rw-r--r--scene/2d/canvas_item.h23
-rw-r--r--scene/2d/collision_object_2d.cpp12
-rw-r--r--scene/2d/collision_polygon_2d.cpp24
-rw-r--r--scene/2d/collision_polygon_2d.h4
-rw-r--r--scene/2d/collision_shape_2d.cpp4
-rw-r--r--scene/2d/joints_2d.cpp10
-rw-r--r--scene/2d/node_2d.cpp46
-rw-r--r--scene/2d/node_2d.h7
-rw-r--r--scene/2d/parallax_background.cpp6
-rw-r--r--scene/2d/parallax_layer.cpp6
-rw-r--r--scene/2d/particles_2d.cpp88
-rw-r--r--scene/2d/particles_2d.h14
-rw-r--r--scene/2d/path_2d.cpp8
-rw-r--r--scene/2d/physics_body_2d.cpp178
-rw-r--r--scene/2d/physics_body_2d.h33
-rw-r--r--scene/2d/polygon_2d.cpp1
-rw-r--r--scene/2d/position_2d.cpp6
-rw-r--r--scene/2d/ray_cast_2d.cpp12
-rw-r--r--scene/2d/remote_transform_2d.cpp8
-rw-r--r--scene/2d/remote_transform_2d.h2
-rw-r--r--scene/2d/sample_player_2d.cpp3
-rw-r--r--scene/2d/screen_button.cpp22
-rw-r--r--scene/2d/sound_player_2d.cpp4
-rw-r--r--scene/2d/sprite.cpp26
-rw-r--r--scene/2d/tile_map.cpp224
-rw-r--r--scene/2d/tile_map.h48
-rw-r--r--scene/2d/visibility_notifier_2d.cpp20
-rw-r--r--scene/2d/y_sort.cpp29
-rw-r--r--scene/2d/y_sort.h17
-rw-r--r--scene/3d/SCsub1
-rw-r--r--scene/3d/area.cpp87
-rw-r--r--scene/3d/area.h14
-rw-r--r--scene/3d/baked_light_instance.cpp78
-rw-r--r--scene/3d/baked_light_instance.h42
-rw-r--r--scene/3d/body_shape.cpp28
-rw-r--r--scene/3d/body_shape.h6
-rw-r--r--scene/3d/bone_attachment.cpp8
-rw-r--r--scene/3d/camera.cpp117
-rw-r--r--scene/3d/camera.h11
-rw-r--r--scene/3d/car_body.cpp741
-rw-r--r--scene/3d/car_body.h170
-rw-r--r--scene/3d/collision_object.cpp67
-rw-r--r--scene/3d/collision_object.h9
-rw-r--r--scene/3d/collision_polygon.cpp2
-rw-r--r--scene/3d/editable_shape.cpp85
-rw-r--r--scene/3d/editable_shape.h73
-rw-r--r--scene/3d/follow_camera.cpp778
-rw-r--r--scene/3d/follow_camera.h180
-rw-r--r--scene/3d/immediate_geometry.cpp52
-rw-r--r--scene/3d/immediate_geometry.h5
-rw-r--r--scene/3d/interpolated_camera.cpp10
-rw-r--r--scene/3d/light.cpp55
-rw-r--r--scene/3d/light.h8
-rw-r--r--scene/3d/mesh_instance.cpp21
-rw-r--r--scene/3d/navigation.cpp57
-rw-r--r--scene/3d/navigation.h8
-rw-r--r--scene/3d/navigation_mesh.cpp12
-rw-r--r--scene/3d/path.cpp720
-rw-r--r--scene/3d/physics_body.cpp88
-rw-r--r--scene/3d/physics_body.h14
-rw-r--r--scene/3d/physics_joint.cpp29
-rw-r--r--scene/3d/physics_joint.h5
-rw-r--r--scene/3d/proximity_group.cpp4
-rw-r--r--scene/3d/quad.cpp6
-rw-r--r--scene/3d/ray_cast.cpp68
-rw-r--r--scene/3d/ray_cast.h9
-rw-r--r--scene/3d/room_instance.cpp2
-rw-r--r--scene/3d/skeleton.cpp20
-rw-r--r--scene/3d/skeleton.h2
-rw-r--r--scene/3d/spatial.cpp24
-rw-r--r--scene/3d/spatial.h2
-rw-r--r--scene/3d/spatial_sample_player.cpp1
-rw-r--r--scene/3d/spatial_stream_player.cpp4
-rw-r--r--scene/3d/sprite_3d.cpp14
-rw-r--r--scene/3d/vehicle_body.cpp17
-rw-r--r--scene/3d/visibility_notifier.cpp14
-rw-r--r--scene/3d/visual_instance.cpp22
-rw-r--r--scene/3d/visual_instance.h1
-rw-r--r--scene/SCsub2
-rw-r--r--scene/animation/animation_cache.cpp10
-rw-r--r--scene/animation/animation_cache.h2
-rw-r--r--scene/animation/animation_player.cpp37
-rw-r--r--scene/animation/animation_player.h5
-rw-r--r--scene/animation/animation_tree_player.cpp7
-rw-r--r--scene/animation/tween.cpp199
-rw-r--r--scene/animation/tween.h45
-rw-r--r--scene/audio/event_player.cpp16
-rw-r--r--scene/audio/sample_player.cpp1
-rw-r--r--scene/audio/sound_room_params.cpp10
-rw-r--r--scene/audio/stream_player.cpp12
-rw-r--r--scene/gui/base_button.cpp66
-rw-r--r--scene/gui/base_button.h20
-rw-r--r--scene/gui/box_container.cpp4
-rw-r--r--scene/gui/button_group.cpp5
-rw-r--r--scene/gui/container.cpp6
-rw-r--r--scene/gui/control.cpp178
-rw-r--r--scene/gui/dialogs.cpp4
-rw-r--r--scene/gui/empty_control.cpp59
-rw-r--r--scene/gui/empty_control.h48
-rw-r--r--scene/gui/graph_edit.cpp586
-rw-r--r--scene/gui/graph_edit.h100
-rw-r--r--scene/gui/graph_node.cpp583
-rw-r--r--scene/gui/graph_node.h101
-rw-r--r--scene/gui/grid_container.cpp1
-rw-r--r--scene/gui/label.cpp7
-rw-r--r--scene/gui/line_edit.cpp2
-rw-r--r--scene/gui/menu_button.cpp1
-rw-r--r--scene/gui/option_button.cpp2
-rw-r--r--scene/gui/popup.cpp15
-rw-r--r--scene/gui/popup_menu.cpp21
-rw-r--r--scene/gui/popup_menu.h4
-rw-r--r--scene/gui/range.cpp4
-rw-r--r--scene/gui/reference_frame.cpp4
-rw-r--r--scene/gui/scroll_bar.cpp16
-rw-r--r--scene/gui/scroll_container.cpp2
-rw-r--r--scene/gui/spin_box.cpp2
-rw-r--r--scene/gui/tab_container.cpp33
-rw-r--r--scene/gui/tab_container.h2
-rw-r--r--scene/gui/text_edit.cpp2404
-rw-r--r--scene/gui/text_edit.h23
-rw-r--r--scene/gui/texture_button.cpp81
-rw-r--r--scene/gui/texture_button.h7
-rw-r--r--scene/gui/tree.cpp20
-rw-r--r--scene/gui/video_player.cpp39
-rw-r--r--scene/gui/video_player.h2
-rw-r--r--scene/io/resource_format_image.cpp47
-rw-r--r--scene/io/scene_format_object.cpp851
-rw-r--r--scene/io/scene_format_object.h128
-rw-r--r--scene/io/scene_format_script.cpp65
-rw-r--r--scene/io/scene_format_script.h45
-rw-r--r--scene/io/scene_loader.cpp161
-rw-r--r--scene/io/scene_loader.h90
-rw-r--r--scene/io/scene_saver.cpp94
-rw-r--r--scene/io/scene_saver.h80
-rw-r--r--scene/main/canvas_layer.cpp6
-rw-r--r--scene/main/node.cpp200
-rw-r--r--scene/main/node.h22
-rw-r--r--scene/main/scene_main_loop.cpp152
-rw-r--r--scene/main/scene_main_loop.h24
-rw-r--r--scene/main/timer.cpp7
-rw-r--r--scene/main/viewport.cpp110
-rw-r--r--scene/main/viewport.h9
-rw-r--r--scene/register_scene_types.cpp98
-rw-r--r--scene/resources/SCsub1
-rw-r--r--scene/resources/animation.cpp287
-rw-r--r--scene/resources/animation.h5
-rw-r--r--scene/resources/audio_stream_resampled.cpp30
-rw-r--r--scene/resources/audio_stream_resampled.h4
-rw-r--r--scene/resources/baked_light.cpp94
-rw-r--r--scene/resources/baked_light.h25
-rw-r--r--scene/resources/circle_shape_2d.cpp4
-rw-r--r--scene/resources/curve.cpp6
-rw-r--r--scene/resources/default_theme/default_theme.cpp19
-rw-r--r--scene/resources/default_theme/graph_node.pngbin0 -> 770 bytes
-rw-r--r--scene/resources/default_theme/graph_node_close.pngbin0 -> 243 bytes
-rw-r--r--scene/resources/default_theme/graph_port.pngbin0 -> 509 bytes
-rw-r--r--scene/resources/default_theme/theme_data.h15
-rw-r--r--scene/resources/image_path_finder.cpp427
-rw-r--r--scene/resources/image_path_finder.h84
-rw-r--r--scene/resources/material.cpp177
-rw-r--r--scene/resources/material.h70
-rw-r--r--scene/resources/mesh.cpp246
-rw-r--r--scene/resources/mesh.h3
-rw-r--r--scene/resources/mikktspace.c1890
-rw-r--r--scene/resources/mikktspace.h145
-rw-r--r--scene/resources/packed_scene.cpp50
-rw-r--r--scene/resources/polygon_path_finder.cpp4
-rw-r--r--scene/resources/scene_preloader.cpp853
-rw-r--r--scene/resources/shader.cpp61
-rw-r--r--scene/resources/shader.h44
-rw-r--r--scene/resources/shader_graph.cpp2532
-rw-r--r--scene/resources/shader_graph.h413
-rw-r--r--scene/resources/shape_2d.cpp2
-rw-r--r--scene/resources/surface_tool.cpp206
-rw-r--r--scene/resources/surface_tool.h10
-rw-r--r--scene/resources/texture.cpp4
-rw-r--r--scene/resources/texture.h2
-rw-r--r--scene/resources/video_stream.cpp1
-rw-r--r--scene/resources/video_stream.h6
-rw-r--r--scene/resources/world_2d.cpp4
-rw-r--r--scene/scene_binds.cpp55
-rw-r--r--scene/scene_binds.h62
-rw-r--r--scene/scene_string_names.cpp18
-rw-r--r--scene/scene_string_names.h17
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
new file mode 100644
index 0000000000..3adccf2c3b
--- /dev/null
+++ b/scene/resources/default_theme/graph_node.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_node_close.png b/scene/resources/default_theme/graph_node_close.png
new file mode 100644
index 0000000000..ea5b510418
--- /dev/null
+++ b/scene/resources/default_theme/graph_node_close.png
Binary files differ
diff --git a/scene/resources/default_theme/graph_port.png b/scene/resources/default_theme/graph_port.png
new file mode 100644
index 0000000000..92f425f977
--- /dev/null
+++ b/scene/resources/default_theme/graph_port.png
Binary files differ
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;
};