summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/animated_sprite.cpp140
-rw-r--r--scene/2d/animated_sprite.h17
-rw-r--r--scene/2d/area_2d.cpp25
-rw-r--r--scene/2d/area_2d.h5
-rw-r--r--scene/2d/audio_stream_player_2d.cpp53
-rw-r--r--scene/2d/audio_stream_player_2d.h34
-rw-r--r--scene/2d/back_buffer_copy.cpp9
-rw-r--r--scene/2d/back_buffer_copy.h6
-rw-r--r--scene/2d/camera_2d.cpp32
-rw-r--r--scene/2d/camera_2d.h5
-rw-r--r--scene/2d/canvas_item.cpp63
-rw-r--r--scene/2d/canvas_item.h60
-rw-r--r--scene/2d/canvas_modulate.cpp5
-rw-r--r--scene/2d/canvas_modulate.h5
-rw-r--r--scene/2d/collision_object_2d.cpp19
-rw-r--r--scene/2d/collision_object_2d.h7
-rw-r--r--scene/2d/collision_polygon_2d.cpp41
-rw-r--r--scene/2d/collision_polygon_2d.h9
-rw-r--r--scene/2d/collision_shape_2d.cpp36
-rw-r--r--scene/2d/collision_shape_2d.h9
-rw-r--r--scene/2d/joints_2d.cpp8
-rw-r--r--scene/2d/joints_2d.h5
-rw-r--r--scene/2d/light_2d.cpp43
-rw-r--r--scene/2d/light_2d.h9
-rw-r--r--scene/2d/light_occluder_2d.cpp11
-rw-r--r--scene/2d/light_occluder_2d.h7
-rw-r--r--scene/2d/line_2d.cpp47
-rw-r--r--scene/2d/line_2d.h9
-rw-r--r--scene/2d/line_builder.cpp19
-rw-r--r--scene/2d/line_builder.h6
-rw-r--r--scene/2d/mesh_instance_2d.cpp106
-rw-r--r--scene/2d/mesh_instance_2d.h63
-rw-r--r--scene/2d/navigation2d.cpp11
-rw-r--r--scene/2d/navigation2d.h7
-rw-r--r--scene/2d/navigation_polygon.cpp77
-rw-r--r--scene/2d/navigation_polygon.h14
-rw-r--r--scene/2d/node_2d.cpp86
-rw-r--r--scene/2d/node_2d.h19
-rw-r--r--scene/2d/parallax_background.cpp5
-rw-r--r--scene/2d/parallax_background.h5
-rw-r--r--scene/2d/parallax_layer.cpp8
-rw-r--r--scene/2d/parallax_layer.h5
-rw-r--r--scene/2d/particles_2d.cpp16
-rw-r--r--scene/2d/particles_2d.h6
-rw-r--r--scene/2d/path_2d.cpp140
-rw-r--r--scene/2d/path_2d.h13
-rw-r--r--scene/2d/path_texture.cpp5
-rw-r--r--scene/2d/path_texture.h5
-rw-r--r--scene/2d/physics_body_2d.cpp57
-rw-r--r--scene/2d/physics_body_2d.h15
-rw-r--r--scene/2d/polygon_2d.cpp304
-rw-r--r--scene/2d/polygon_2d.h51
-rw-r--r--scene/2d/position_2d.cpp9
-rw-r--r--scene/2d/position_2d.h6
-rw-r--r--scene/2d/ray_cast_2d.cpp15
-rw-r--r--scene/2d/ray_cast_2d.h5
-rw-r--r--scene/2d/remote_transform_2d.cpp5
-rw-r--r--scene/2d/remote_transform_2d.h10
-rw-r--r--scene/2d/screen_button.cpp9
-rw-r--r--scene/2d/screen_button.h6
-rw-r--r--scene/2d/skeleton_2d.cpp308
-rw-r--r--scene/2d/skeleton_2d.h109
-rw-r--r--scene/2d/sprite.cpp204
-rw-r--r--scene/2d/sprite.h18
-rw-r--r--scene/2d/tile_map.cpp187
-rw-r--r--scene/2d/tile_map.h10
-rw-r--r--scene/2d/visibility_notifier_2d.cpp13
-rw-r--r--scene/2d/visibility_notifier_2d.h6
-rw-r--r--scene/2d/y_sort.cpp5
-rw-r--r--scene/2d/y_sort.h5
-rw-r--r--scene/3d/area.cpp19
-rw-r--r--scene/3d/area.h5
-rw-r--r--scene/3d/arvr_nodes.cpp14
-rw-r--r--scene/3d/arvr_nodes.h4
-rw-r--r--scene/3d/audio_stream_player_3d.cpp60
-rw-r--r--scene/3d/audio_stream_player_3d.h34
-rw-r--r--scene/3d/baked_lightmap.cpp203
-rw-r--r--scene/3d/baked_lightmap.h59
-rw-r--r--scene/3d/bone_attachment.cpp53
-rw-r--r--scene/3d/bone_attachment.h9
-rw-r--r--scene/3d/camera.cpp205
-rw-r--r--scene/3d/camera.h22
-rw-r--r--scene/3d/collision_object.cpp19
-rw-r--r--scene/3d/collision_object.h7
-rw-r--r--scene/3d/collision_polygon.cpp30
-rw-r--r--scene/3d/collision_polygon.h9
-rw-r--r--scene/3d/collision_shape.cpp22
-rw-r--r--scene/3d/collision_shape.h7
-rw-r--r--scene/3d/gi_probe.cpp7
-rw-r--r--scene/3d/gi_probe.h5
-rw-r--r--scene/3d/immediate_geometry.cpp5
-rw-r--r--scene/3d/immediate_geometry.h5
-rw-r--r--scene/3d/interpolated_camera.cpp13
-rw-r--r--scene/3d/interpolated_camera.h5
-rw-r--r--scene/3d/light.cpp17
-rw-r--r--scene/3d/light.h5
-rw-r--r--scene/3d/listener.cpp5
-rw-r--r--scene/3d/listener.h5
-rw-r--r--scene/3d/mesh_instance.cpp5
-rw-r--r--scene/3d/mesh_instance.h5
-rw-r--r--scene/3d/multimesh_instance.cpp5
-rw-r--r--scene/3d/multimesh_instance.h5
-rw-r--r--scene/3d/navigation.cpp10
-rw-r--r--scene/3d/navigation.h7
-rw-r--r--scene/3d/navigation_mesh.cpp15
-rw-r--r--scene/3d/navigation_mesh.h5
-rw-r--r--scene/3d/particles.cpp120
-rw-r--r--scene/3d/particles.h6
-rw-r--r--scene/3d/path.cpp81
-rw-r--r--scene/3d/path.h9
-rw-r--r--scene/3d/physics_body.cpp1166
-rw-r--r--scene/3d/physics_body.h283
-rw-r--r--scene/3d/physics_joint.cpp29
-rw-r--r--scene/3d/physics_joint.h8
-rw-r--r--scene/3d/portal.cpp5
-rw-r--r--scene/3d/portal.h8
-rw-r--r--scene/3d/position_3d.cpp5
-rw-r--r--scene/3d/position_3d.h5
-rw-r--r--scene/3d/proximity_group.cpp42
-rw-r--r--scene/3d/proximity_group.h17
-rw-r--r--scene/3d/ray_cast.cpp17
-rw-r--r--scene/3d/ray_cast.h5
-rw-r--r--scene/3d/reflection_probe.cpp9
-rw-r--r--scene/3d/reflection_probe.h5
-rw-r--r--scene/3d/remote_transform.cpp4
-rw-r--r--scene/3d/remote_transform.h5
-rw-r--r--scene/3d/room_instance.cpp5
-rw-r--r--scene/3d/room_instance.h7
-rw-r--r--scene/3d/scenario_fx.cpp16
-rw-r--r--scene/3d/scenario_fx.h5
-rw-r--r--scene/3d/skeleton.cpp213
-rw-r--r--scene/3d/skeleton.h52
-rw-r--r--scene/3d/spatial.cpp128
-rw-r--r--scene/3d/spatial.h32
-rw-r--r--scene/3d/spatial_velocity_tracker.cpp32
-rw-r--r--scene/3d/spatial_velocity_tracker.h30
-rw-r--r--scene/3d/sprite_3d.cpp6
-rw-r--r--scene/3d/sprite_3d.h5
-rw-r--r--scene/3d/vehicle_body.cpp101
-rw-r--r--scene/3d/vehicle_body.h26
-rw-r--r--scene/3d/visibility_notifier.cpp11
-rw-r--r--scene/3d/visibility_notifier.h5
-rw-r--r--scene/3d/visual_instance.cpp5
-rw-r--r--scene/3d/visual_instance.h5
-rw-r--r--scene/3d/voxel_light_baker.cpp290
-rw-r--r--scene/3d/voxel_light_baker.h39
-rw-r--r--scene/animation/animation_cache.cpp9
-rw-r--r--scene/animation/animation_cache.h5
-rw-r--r--scene/animation/animation_player.cpp204
-rw-r--r--scene/animation/animation_player.h10
-rw-r--r--scene/animation/animation_tree_player.cpp37
-rw-r--r--scene/animation/animation_tree_player.h6
-rw-r--r--scene/animation/tween.cpp98
-rw-r--r--scene/animation/tween.h5
-rw-r--r--scene/animation/tween_interpolaters.cpp5
-rw-r--r--scene/audio/audio_player.cpp21
-rw-r--r--scene/audio/audio_player.h9
-rw-r--r--scene/gui/base_button.cpp52
-rw-r--r--scene/gui/base_button.h13
-rw-r--r--scene/gui/box_container.cpp5
-rw-r--r--scene/gui/box_container.h5
-rw-r--r--scene/gui/button.cpp5
-rw-r--r--scene/gui/button.h8
-rw-r--r--scene/gui/center_container.cpp5
-rw-r--r--scene/gui/center_container.h5
-rw-r--r--scene/gui/check_box.cpp7
-rw-r--r--scene/gui/check_box.h5
-rw-r--r--scene/gui/check_button.cpp5
-rw-r--r--scene/gui/check_button.h5
-rw-r--r--scene/gui/color_picker.cpp134
-rw-r--r--scene/gui/color_picker.h16
-rw-r--r--scene/gui/color_rect.cpp5
-rw-r--r--scene/gui/color_rect.h5
-rw-r--r--scene/gui/container.cpp16
-rw-r--r--scene/gui/container.h5
-rw-r--r--scene/gui/control.cpp186
-rw-r--r--scene/gui/control.h25
-rw-r--r--scene/gui/dialogs.cpp18
-rw-r--r--scene/gui/dialogs.h7
-rw-r--r--scene/gui/file_dialog.cpp46
-rw-r--r--scene/gui/file_dialog.h7
-rw-r--r--scene/gui/gradient_edit.cpp15
-rw-r--r--scene/gui/gradient_edit.h18
-rw-r--r--scene/gui/graph_edit.cpp20
-rw-r--r--scene/gui/graph_edit.h7
-rw-r--r--scene/gui/graph_node.cpp9
-rw-r--r--scene/gui/graph_node.h5
-rw-r--r--scene/gui/grid_container.cpp168
-rw-r--r--scene/gui/grid_container.h6
-rw-r--r--scene/gui/item_list.cpp156
-rw-r--r--scene/gui/item_list.h20
-rw-r--r--scene/gui/label.cpp35
-rw-r--r--scene/gui/label.h5
-rw-r--r--scene/gui/line_edit.cpp165
-rw-r--r--scene/gui/line_edit.h18
-rw-r--r--scene/gui/link_button.cpp5
-rw-r--r--scene/gui/link_button.h5
-rw-r--r--scene/gui/margin_container.cpp5
-rw-r--r--scene/gui/margin_container.h5
-rw-r--r--scene/gui/menu_button.cpp37
-rw-r--r--scene/gui/menu_button.h10
-rw-r--r--scene/gui/nine_patch_rect.cpp5
-rw-r--r--scene/gui/nine_patch_rect.h5
-rw-r--r--scene/gui/option_button.cpp98
-rw-r--r--scene/gui/option_button.h8
-rw-r--r--scene/gui/panel.cpp5
-rw-r--r--scene/gui/panel.h5
-rw-r--r--scene/gui/panel_container.cpp5
-rw-r--r--scene/gui/panel_container.h5
-rw-r--r--scene/gui/popup.cpp5
-rw-r--r--scene/gui/popup.h5
-rw-r--r--scene/gui/popup_menu.cpp353
-rw-r--r--scene/gui/popup_menu.h24
-rw-r--r--scene/gui/progress_bar.cpp14
-rw-r--r--scene/gui/progress_bar.h5
-rw-r--r--scene/gui/range.cpp51
-rw-r--r--scene/gui/range.h13
-rw-r--r--scene/gui/reference_rect.cpp5
-rw-r--r--scene/gui/reference_rect.h5
-rw-r--r--scene/gui/rich_text_label.cpp278
-rw-r--r--scene/gui/rich_text_label.h17
-rw-r--r--scene/gui/scroll_bar.cpp85
-rw-r--r--scene/gui/scroll_bar.h5
-rw-r--r--scene/gui/scroll_container.cpp111
-rw-r--r--scene/gui/scroll_container.h11
-rw-r--r--scene/gui/separator.cpp5
-rw-r--r--scene/gui/separator.h5
-rw-r--r--scene/gui/shortcut.cpp5
-rw-r--r--scene/gui/shortcut.h5
-rw-r--r--scene/gui/slider.cpp31
-rw-r--r--scene/gui/slider.h5
-rw-r--r--scene/gui/spin_box.cpp21
-rw-r--r--scene/gui/spin_box.h7
-rw-r--r--scene/gui/split_container.cpp202
-rw-r--r--scene/gui/split_container.h11
-rw-r--r--scene/gui/tab_container.cpp184
-rw-r--r--scene/gui/tab_container.h18
-rw-r--r--scene/gui/tabs.cpp126
-rw-r--r--scene/gui/tabs.h12
-rw-r--r--scene/gui/text_edit.cpp2453
-rw-r--r--scene/gui/text_edit.h247
-rw-r--r--scene/gui/texture_button.cpp70
-rw-r--r--scene/gui/texture_button.h9
-rw-r--r--scene/gui/texture_progress.cpp134
-rw-r--r--scene/gui/texture_progress.h17
-rw-r--r--scene/gui/texture_rect.cpp5
-rw-r--r--scene/gui/texture_rect.h5
-rw-r--r--scene/gui/tool_button.cpp5
-rw-r--r--scene/gui/tool_button.h5
-rw-r--r--scene/gui/tree.cpp739
-rw-r--r--scene/gui/tree.h23
-rw-r--r--scene/gui/video_player.cpp32
-rw-r--r--scene/gui/video_player.h7
-rw-r--r--scene/gui/viewport_container.cpp33
-rw-r--r--scene/gui/viewport_container.h6
-rw-r--r--scene/main/canvas_layer.cpp50
-rw-r--r--scene/main/canvas_layer.h12
-rw-r--r--scene/main/http_request.cpp8
-rw-r--r--scene/main/http_request.h5
-rw-r--r--scene/main/instance_placeholder.cpp29
-rw-r--r--scene/main/instance_placeholder.h6
-rw-r--r--scene/main/node.cpp379
-rw-r--r--scene/main/node.h31
-rw-r--r--scene/main/resource_preloader.cpp7
-rw-r--r--scene/main/resource_preloader.h5
-rw-r--r--scene/main/scene_tree.cpp565
-rw-r--r--scene/main/scene_tree.h66
-rwxr-xr-xscene/main/timer.cpp14
-rwxr-xr-xscene/main/timer.h7
-rw-r--r--scene/main/viewport.cpp330
-rw-r--r--scene/main/viewport.h30
-rw-r--r--scene/register_scene_types.cpp107
-rw-r--r--scene/register_scene_types.h5
-rw-r--r--scene/resources/animation.cpp58
-rw-r--r--scene/resources/animation.h5
-rw-r--r--scene/resources/audio_stream_sample.cpp45
-rw-r--r--scene/resources/audio_stream_sample.h9
-rw-r--r--scene/resources/bit_mask.cpp363
-rw-r--r--scene/resources/bit_mask.h14
-rw-r--r--scene/resources/bounds.cpp5
-rw-r--r--scene/resources/bounds.h5
-rw-r--r--scene/resources/box_shape.cpp5
-rw-r--r--scene/resources/box_shape.h5
-rw-r--r--scene/resources/canvas.cpp5
-rw-r--r--scene/resources/canvas.h5
-rw-r--r--scene/resources/capsule_shape.cpp5
-rw-r--r--scene/resources/capsule_shape.h5
-rw-r--r--scene/resources/capsule_shape_2d.cpp34
-rw-r--r--scene/resources/capsule_shape_2d.h8
-rw-r--r--scene/resources/circle_shape_2d.cpp11
-rw-r--r--scene/resources/circle_shape_2d.h7
-rw-r--r--scene/resources/color_ramp.cpp9
-rw-r--r--scene/resources/color_ramp.h5
-rw-r--r--scene/resources/concave_polygon_shape.cpp29
-rw-r--r--scene/resources/concave_polygon_shape.h8
-rw-r--r--scene/resources/concave_polygon_shape_2d.cpp22
-rw-r--r--scene/resources/concave_polygon_shape_2d.h7
-rw-r--r--scene/resources/convex_polygon_shape.cpp5
-rw-r--r--scene/resources/convex_polygon_shape.h5
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp10
-rw-r--r--scene/resources/convex_polygon_shape_2d.h7
-rw-r--r--scene/resources/curve.cpp177
-rw-r--r--scene/resources/curve.h9
-rw-r--r--scene/resources/default_theme/default_theme.cpp28
-rw-r--r--scene/resources/default_theme/default_theme.h4
-rw-r--r--scene/resources/dynamic_font.cpp636
-rw-r--r--scene/resources/dynamic_font.h93
-rw-r--r--scene/resources/dynamic_font_stb.cpp27
-rw-r--r--scene/resources/dynamic_font_stb.h9
-rw-r--r--scene/resources/environment.cpp15
-rw-r--r--scene/resources/environment.h5
-rw-r--r--scene/resources/font.cpp97
-rw-r--r--scene/resources/font.h62
-rw-r--r--scene/resources/material.cpp80
-rw-r--r--scene/resources/material.h10
-rw-r--r--scene/resources/mesh.cpp45
-rw-r--r--scene/resources/mesh.h5
-rw-r--r--scene/resources/mesh_data_tool.cpp5
-rw-r--r--scene/resources/mesh_data_tool.h5
-rw-r--r--scene/resources/mesh_library.cpp5
-rw-r--r--scene/resources/mesh_library.h5
-rw-r--r--scene/resources/multimesh.cpp9
-rw-r--r--scene/resources/multimesh.h5
-rw-r--r--scene/resources/packed_scene.cpp34
-rw-r--r--scene/resources/packed_scene.h11
-rw-r--r--scene/resources/plane_shape.cpp5
-rw-r--r--scene/resources/plane_shape.h5
-rw-r--r--scene/resources/polygon_path_finder.cpp7
-rw-r--r--scene/resources/polygon_path_finder.h5
-rw-r--r--scene/resources/primitive_meshes.cpp80
-rw-r--r--scene/resources/primitive_meshes.h16
-rw-r--r--scene/resources/ray_shape.cpp28
-rw-r--r--scene/resources/ray_shape.h9
-rw-r--r--scene/resources/rectangle_shape_2d.cpp5
-rw-r--r--scene/resources/rectangle_shape_2d.h5
-rw-r--r--scene/resources/room.cpp5
-rw-r--r--scene/resources/room.h7
-rw-r--r--scene/resources/scene_format_text.cpp45
-rw-r--r--scene/resources/scene_format_text.h9
-rw-r--r--scene/resources/segment_shape_2d.cpp32
-rw-r--r--scene/resources/segment_shape_2d.h12
-rw-r--r--scene/resources/shader.cpp82
-rw-r--r--scene/resources/shader.h22
-rw-r--r--scene/resources/shader_graph.cpp7
-rw-r--r--scene/resources/shader_graph.h5
-rw-r--r--scene/resources/shape.cpp5
-rw-r--r--scene/resources/shape.h5
-rw-r--r--scene/resources/shape_2d.cpp5
-rw-r--r--scene/resources/shape_2d.h7
-rw-r--r--scene/resources/shape_line_2d.cpp20
-rw-r--r--scene/resources/shape_line_2d.h7
-rw-r--r--scene/resources/sky_box.cpp5
-rw-r--r--scene/resources/sky_box.h11
-rw-r--r--scene/resources/space_2d.cpp5
-rw-r--r--scene/resources/space_2d.h5
-rw-r--r--scene/resources/sphere_shape.cpp5
-rw-r--r--scene/resources/sphere_shape.h5
-rw-r--r--scene/resources/style_box.cpp39
-rw-r--r--scene/resources/style_box.h13
-rw-r--r--scene/resources/surface_tool.cpp15
-rw-r--r--scene/resources/surface_tool.h7
-rw-r--r--scene/resources/texture.cpp43
-rw-r--r--scene/resources/texture.h7
-rw-r--r--scene/resources/theme.cpp5
-rw-r--r--scene/resources/theme.h5
-rw-r--r--scene/resources/tile_set.cpp85
-rw-r--r--scene/resources/tile_set.h27
-rw-r--r--scene/resources/video_stream.cpp5
-rw-r--r--scene/resources/video_stream.h5
-rw-r--r--scene/resources/world.cpp8
-rw-r--r--scene/resources/world.h5
-rw-r--r--scene/resources/world_2d.cpp9
-rw-r--r--scene/resources/world_2d.h5
-rw-r--r--scene/scene_string_names.cpp7
-rw-r--r--scene/scene_string_names.h7
375 files changed, 12567 insertions, 5651 deletions
diff --git a/scene/2d/animated_sprite.cpp b/scene/2d/animated_sprite.cpp
index de28fef929..54194ff543 100644
--- a/scene/2d/animated_sprite.cpp
+++ b/scene/2d/animated_sprite.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,13 +27,62 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "animated_sprite.h"
#include "os/os.h"
#include "scene/scene_string_names.h"
#define NORMAL_SUFFIX "_normal"
-////////////////////////////
+Dictionary AnimatedSprite::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["offset"] = offset;
+ return state;
+}
+
+void AnimatedSprite::_edit_set_state(const Dictionary &p_state) {
+ Node2D::_edit_set_state(p_state);
+ set_offset(p_state["offset"]);
+}
+
+void AnimatedSprite::_edit_set_pivot(const Point2 &p_pivot) {
+ set_offset(get_offset() - p_pivot);
+ set_position(get_transform().xform(p_pivot));
+}
+
+Point2 AnimatedSprite::_edit_get_pivot() const {
+ return Vector2();
+}
+
+bool AnimatedSprite::_edit_use_pivot() const {
+ return true;
+}
+
+Rect2 AnimatedSprite::_edit_get_rect() const {
+ if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
+ return Node2D::_edit_get_rect();
+ }
+
+ Ref<Texture> t;
+ if (animation)
+ t = frames->get_frame(animation, frame);
+ if (t.is_null())
+ return Node2D::_edit_get_rect();
+ Size2 s = t->get_size();
+
+ Point2 ofs = offset;
+ if (centered)
+ ofs -= s / 2;
+
+ if (s == Size2(0, 0))
+ s = Size2(1, 1);
+
+ return Rect2(ofs, s);
+}
+
+bool AnimatedSprite::_edit_use_rect() const {
+ return true;
+}
void SpriteFrames::add_frame(const StringName &p_anim, const Ref<Texture> &p_frame, int p_at_pos) {
@@ -239,7 +288,7 @@ void SpriteFrames::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_animations"), &SpriteFrames::_set_animations);
ClassDB::bind_method(D_METHOD("_get_animations"), &SpriteFrames::_get_animations);
- ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_animations", "_get_animations"); //compatibility
+ ADD_PROPERTYNZ(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_animations", "_get_animations"); //compatibility
}
SpriteFrames::SpriteFrames() {
@@ -247,20 +296,6 @@ SpriteFrames::SpriteFrames() {
add_animation(SceneStringNames::get_singleton()->_default);
}
-void AnimatedSprite::_edit_set_pivot(const Point2 &p_pivot) {
-
- set_offset(p_pivot);
-}
-
-Point2 AnimatedSprite::_edit_get_pivot() const {
-
- return get_offset();
-}
-bool AnimatedSprite::_edit_use_pivot() const {
-
- return true;
-}
-
void AnimatedSprite::_validate_property(PropertyInfo &property) const {
if (!frames.is_valid())
@@ -316,7 +351,7 @@ void AnimatedSprite::_notification(int p_what) {
if (frame < 0)
return;
- float speed = frames->get_animation_speed(animation);
+ float speed = frames->get_animation_speed(animation) * speed_scale;
if (speed == 0)
return; //do nothing
@@ -326,7 +361,7 @@ void AnimatedSprite::_notification(int p_what) {
if (timeout <= 0) {
- timeout = 1.0 / speed;
+ timeout = _get_frame_duration();
int fc = frames->get_frame_count(animation);
if (frame >= fc - 1) {
@@ -446,6 +481,22 @@ int AnimatedSprite::get_frame() const {
return frame;
}
+void AnimatedSprite::set_speed_scale(float p_speed_scale) {
+
+ float elapsed = _get_frame_duration() - timeout;
+
+ speed_scale = MAX(p_speed_scale, 0.0f);
+
+ // We adapt the timeout so that the animation speed adapts as soon as the speed scale is changed
+ _reset_timeout();
+ timeout -= elapsed;
+}
+
+float AnimatedSprite::get_speed_scale() const {
+
+ return speed_scale;
+}
+
void AnimatedSprite::set_centered(bool p_center) {
centered = p_center;
@@ -490,29 +541,6 @@ bool AnimatedSprite::is_flipped_v() const {
return vflip;
}
-Rect2 AnimatedSprite::_edit_get_rect() const {
-
- if (!frames.is_valid() || !frames->has_animation(animation) || frame < 0 || frame >= frames->get_frame_count(animation)) {
- return Node2D::_edit_get_rect();
- }
-
- Ref<Texture> t;
- if (animation)
- t = frames->get_frame(animation, frame);
- if (t.is_null())
- return Node2D::_edit_get_rect();
- Size2i s = t->get_size();
-
- Point2 ofs = offset;
- if (centered)
- ofs -= s / 2;
-
- if (s == Size2(0, 0))
- s = Size2(1, 1);
-
- return Rect2(ofs, s);
-}
-
void AnimatedSprite::_res_changed() {
set_frame(frame);
@@ -552,21 +580,22 @@ bool AnimatedSprite::is_playing() const {
return playing;
}
+float AnimatedSprite::_get_frame_duration() {
+ if (frames.is_valid() && frames->has_animation(animation)) {
+ float speed = frames->get_animation_speed(animation) * speed_scale;
+ if (speed > 0) {
+ return 1.0 / speed;
+ }
+ }
+ return 0.0;
+}
+
void AnimatedSprite::_reset_timeout() {
if (!playing)
return;
- if (frames.is_valid() && frames->has_animation(animation)) {
- float speed = frames->get_animation_speed(animation);
- if (speed > 0) {
- timeout = 1.0 / speed;
- } else {
- timeout = 0;
- }
- } else {
- timeout = 0;
- }
+ timeout = _get_frame_duration();
}
void AnimatedSprite::set_animation(const StringName &p_animation) {
@@ -624,6 +653,9 @@ void AnimatedSprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_frame", "frame"), &AnimatedSprite::set_frame);
ClassDB::bind_method(D_METHOD("get_frame"), &AnimatedSprite::get_frame);
+ ClassDB::bind_method(D_METHOD("set_speed_scale", "speed_scale"), &AnimatedSprite::set_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimatedSprite::get_speed_scale);
+
ClassDB::bind_method(D_METHOD("_res_changed"), &AnimatedSprite::_res_changed);
ADD_SIGNAL(MethodInfo("frame_changed"));
@@ -632,6 +664,7 @@ void AnimatedSprite::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "frames", PROPERTY_HINT_RESOURCE_TYPE, "SpriteFrames"), "set_sprite_frames", "get_sprite_frames");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "animation"), "set_animation", "get_animation");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "frame", PROPERTY_HINT_SPRITE_FRAME), "set_frame", "get_frame");
+ ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "speed_scale"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "playing"), "_set_playing", "_is_playing");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "centered"), "set_centered", "is_centered");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
@@ -646,6 +679,7 @@ AnimatedSprite::AnimatedSprite() {
vflip = false;
frame = 0;
+ speed_scale = 1.0f;
playing = false;
animation = "default";
timeout = 0;
diff --git a/scene/2d/animated_sprite.h b/scene/2d/animated_sprite.h
index a8d0db021a..be5b1ef6d6 100644
--- a/scene/2d/animated_sprite.h
+++ b/scene/2d/animated_sprite.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ANIMATED_SPRITE_H
#define ANIMATED_SPRITE_H
@@ -128,6 +129,7 @@ class AnimatedSprite : public Node2D {
bool playing;
StringName animation;
int frame;
+ float speed_scale;
bool centered;
Point2 offset;
@@ -139,6 +141,7 @@ class AnimatedSprite : public Node2D {
void _res_changed();
+ float _get_frame_duration();
void _reset_timeout();
void _set_playing(bool p_playing);
bool _is_playing() const;
@@ -149,9 +152,14 @@ protected:
virtual void _validate_property(PropertyInfo &property) const;
public:
+ virtual Dictionary _edit_get_state() const;
+ virtual void _edit_set_state(const Dictionary &p_state);
+
virtual void _edit_set_pivot(const Point2 &p_pivot);
virtual Point2 _edit_get_pivot() const;
virtual bool _edit_use_pivot() const;
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
void set_sprite_frames(const Ref<SpriteFrames> &p_frames);
Ref<SpriteFrames> get_sprite_frames() const;
@@ -166,6 +174,9 @@ public:
void set_frame(int p_frame);
int get_frame() const;
+ void set_speed_scale(float p_speed_scale);
+ float get_speed_scale() const;
+
void set_centered(bool p_center);
bool is_centered() const;
@@ -181,8 +192,6 @@ public:
void set_modulate(const Color &p_color);
Color get_modulate() const;
- virtual Rect2 _edit_get_rect() const;
-
virtual String get_configuration_warning() const;
AnimatedSprite();
};
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 80f9bf0f9f..c375374dce 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "area_2d.h"
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
@@ -169,7 +170,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, int p_instance, int p_
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -196,7 +197,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, int p_instance, int p_
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (E->get().in_tree)
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
}
@@ -270,7 +271,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, int p_instance, int p_
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree, make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
}
@@ -297,7 +298,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, int p_instance, int p_
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree);
if (E->get().in_tree)
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
}
@@ -337,7 +338,7 @@ void Area2D::_clear_monitoring() {
//ERR_CONTINUE(!node);
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (!E->get().in_tree)
continue;
@@ -367,7 +368,7 @@ void Area2D::_clear_monitoring() {
//ERR_CONTINUE(!node);
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree);
if (!E->get().in_tree)
continue;
@@ -398,7 +399,7 @@ void Area2D::set_monitoring(bool p_enable) {
if (p_enable == monitoring)
return;
if (locked) {
- ERR_EXPLAIN("Function blocked during in/out signal. Use call_deferred(\"set_enable_monitoring\",true/false)");
+ ERR_EXPLAIN("Function blocked during in/out signal. Use call_deferred(\"set_monitoring\",true/false)");
}
ERR_FAIL_COND(locked);
@@ -665,11 +666,11 @@ void Area2D::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.001"), "set_gravity", "get_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_linear_damp", "get_linear_damp");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_angular_damp", "get_angular_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_linear_damp", "get_linear_damp");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "0,100,0.01,or_greater"), "set_angular_damp", "get_angular_damp");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,128,1"), "set_priority", "get_priority");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitoring"), "set_monitoring", "is_monitoring");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "monitorable"), "set_monitorable", "is_monitorable");
diff --git a/scene/2d/area_2d.h b/scene/2d/area_2d.h
index 09ccb364e6..0fda9b867d 100644
--- a/scene/2d/area_2d.h
+++ b/scene/2d/area_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef AREA_2D_H
#define AREA_2D_H
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index 937a026e34..54541293fd 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -1,3 +1,32 @@
+/*************************************************************************/
+/* audio_stream_player_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "audio_stream_player_2d.h"
@@ -25,7 +54,7 @@ void AudioStreamPlayer2D::_mix_audio() {
int buffer_size = mix_buffer.size();
//mix
- stream_playback->mix(buffer, 1.0, buffer_size);
+ stream_playback->mix(buffer, pitch_scale, buffer_size);
//write all outputs
for (int i = 0; i < output_count; i++) {
@@ -166,7 +195,7 @@ void AudioStreamPlayer2D::_notification(int p_what) {
float dist = global_pos.distance_to(screen_in_global); //distance to screen center
if (dist > max_distance)
- continue; //cant hear this sound in this viewport
+ continue; //can't hear this sound in this viewport
float multiplier = Math::pow(1.0f - dist / max_distance, attenuation);
multiplier *= Math::db2linear(volume_db); //also apply player volume!
@@ -197,14 +226,14 @@ void AudioStreamPlayer2D::_notification(int p_what) {
setseek = setplay;
active = true;
setplay = -1;
- //do not update, this makes it easier to animate (will shut off otherise)
+ //do not update, this makes it easier to animate (will shut off otherwise)
//_change_notify("playing"); //update property in editor
}
//stop playing if no longer active
if (!active) {
set_physics_process_internal(false);
- //do not update, this makes it easier to animate (will shut off otherise)
+ //do not update, this makes it easier to animate (will shut off otherwise)
//_change_notify("playing"); //update property in editor
emit_signal("finished");
}
@@ -250,6 +279,13 @@ float AudioStreamPlayer2D::get_volume_db() const {
return volume_db;
}
+void AudioStreamPlayer2D::set_pitch_scale(float p_pitch_scale) {
+ pitch_scale = p_pitch_scale;
+}
+float AudioStreamPlayer2D::get_pitch_scale() const {
+ return pitch_scale;
+}
+
void AudioStreamPlayer2D::play(float p_from_pos) {
if (stream_playback.is_valid()) {
@@ -390,6 +426,9 @@ void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer2D::set_volume_db);
ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer2D::get_volume_db);
+ ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer2D::set_pitch_scale);
+ ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer2D::get_pitch_scale);
+
ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer2D::play, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer2D::seek);
ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer2D::stop);
@@ -419,10 +458,11 @@ void AudioStreamPlayer2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "1,65536,1"), "set_max_distance", "get_max_distance");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING), "set_attenuation", "get_attenuation");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "1,4096,1,or_greater"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_attenuation", "get_attenuation");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
@@ -432,6 +472,7 @@ void AudioStreamPlayer2D::_bind_methods() {
AudioStreamPlayer2D::AudioStreamPlayer2D() {
volume_db = 0;
+ pitch_scale = 1.0;
autoplay = false;
setseek = -1;
active = false;
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index 85104fce21..9ae8e3a518 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* audio_stream_player_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 AUDIO_STREAM_PLAYER_2D_H
#define AUDIO_STREAM_PLAYER_2D_H
@@ -40,6 +70,7 @@ private:
volatile float setplay;
float volume_db;
+ float pitch_scale;
bool autoplay;
StringName bus;
@@ -68,6 +99,9 @@ public:
void set_volume_db(float p_volume);
float get_volume_db() const;
+ void set_pitch_scale(float p_pitch_scale);
+ float get_pitch_scale() const;
+
void play(float p_from_pos = 0.0);
void seek(float p_seconds);
void stop();
diff --git a/scene/2d/back_buffer_copy.cpp b/scene/2d/back_buffer_copy.cpp
index e4f52a227a..caa1adebdb 100644
--- a/scene/2d/back_buffer_copy.cpp
+++ b/scene/2d/back_buffer_copy.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "back_buffer_copy.h"
void BackBufferCopy::_update_copy_mode() {
@@ -54,6 +55,10 @@ Rect2 BackBufferCopy::_edit_get_rect() const {
return rect;
}
+bool BackBufferCopy::_edit_use_rect() const {
+ return true;
+}
+
void BackBufferCopy::set_rect(const Rect2 &p_rect) {
rect = p_rect;
diff --git a/scene/2d/back_buffer_copy.h b/scene/2d/back_buffer_copy.h
index cfd632d755..752d56de2b 100644
--- a/scene/2d/back_buffer_copy.h
+++ b/scene/2d/back_buffer_copy.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BACKBUFFERCOPY_H
#define BACKBUFFERCOPY_H
@@ -53,6 +54,7 @@ protected:
public:
Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
void set_rect(const Rect2 &p_rect);
Rect2 get_rect() const;
diff --git a/scene/2d/camera_2d.cpp b/scene/2d/camera_2d.cpp
index 3164344d15..3b86ca76ea 100644
--- a/scene/2d/camera_2d.cpp
+++ b/scene/2d/camera_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "camera_2d.h"
#include "core/math/math_funcs.h"
#include "scene/scene_string_names.h"
@@ -90,8 +91,8 @@ Transform2D Camera2D::get_camera_transform() {
if (anchor_mode == ANCHOR_MODE_DRAG_CENTER) {
if (h_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {
- camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * drag_margin[MARGIN_RIGHT]));
- camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * drag_margin[MARGIN_LEFT]));
+ camera_pos.x = MIN(camera_pos.x, (new_camera_pos.x + screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_LEFT]));
+ camera_pos.x = MAX(camera_pos.x, (new_camera_pos.x - screen_size.x * 0.5 * zoom.x * drag_margin[MARGIN_RIGHT]));
} else {
if (h_ofs < 0) {
@@ -103,8 +104,8 @@ Transform2D Camera2D::get_camera_transform() {
if (v_drag_enabled && !Engine::get_singleton()->is_editor_hint()) {
- camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * drag_margin[MARGIN_BOTTOM]));
- camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * drag_margin[MARGIN_TOP]));
+ camera_pos.y = MIN(camera_pos.y, (new_camera_pos.y + screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_TOP]));
+ camera_pos.y = MAX(camera_pos.y, (new_camera_pos.y - screen_size.y * 0.5 * zoom.y * drag_margin[MARGIN_BOTTOM]));
} else {
@@ -142,7 +143,7 @@ Transform2D Camera2D::get_camera_transform() {
if (smoothing_enabled && !Engine::get_singleton()->is_editor_hint()) {
- float c = smoothing * get_physics_process_delta_time();
+ float c = smoothing * get_process_delta_time();
smoothed_camera_pos = ((camera_pos - smoothed_camera_pos) * c) + smoothed_camera_pos;
ret_camera_pos = smoothed_camera_pos;
//camera_pos=camera_pos*(1.0-smoothing)+new_camera_pos*smoothing;
@@ -216,14 +217,14 @@ void Camera2D::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_PHYSICS_PROCESS: {
+ case NOTIFICATION_INTERNAL_PROCESS: {
_update_scroll();
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
- if (!is_physics_processing())
+ if (!is_processing_internal())
_update_scroll();
} break;
@@ -245,7 +246,7 @@ void Camera2D::_notification(int p_what) {
add_to_group(canvas_group_name);
if (Engine::get_singleton()->is_editor_hint()) {
- set_physics_process(false);
+ set_process_internal(false);
}
_update_scroll();
@@ -502,9 +503,9 @@ void Camera2D::set_follow_smoothing(float p_speed) {
smoothing = p_speed;
if (smoothing > 0 && !(is_inside_tree() && Engine::get_singleton()->is_editor_hint()))
- set_physics_process(true);
+ set_process_internal(true);
else
- set_physics_process(false);
+ set_process_internal(false);
}
float Camera2D::get_follow_smoothing() const {
@@ -540,6 +541,7 @@ bool Camera2D::is_v_drag_enabled() const {
void Camera2D::set_v_offset(float p_offset) {
v_ofs = p_offset;
+ _update_scroll();
}
float Camera2D::get_v_offset() const {
@@ -550,6 +552,7 @@ float Camera2D::get_v_offset() const {
void Camera2D::set_h_offset(float p_offset) {
h_ofs = p_offset;
+ _update_scroll();
}
float Camera2D::get_h_offset() const {
@@ -712,6 +715,7 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotating"), "set_rotating", "is_rotating");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "_set_current", "is_current");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "zoom"), "set_zoom", "get_zoom");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
ADD_GROUP("Limit", "limit_");
ADD_PROPERTYI(PropertyInfo(Variant::INT, "limit_left"), "set_limit", "get_limit", MARGIN_LEFT);
@@ -728,6 +732,10 @@ void Camera2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smoothing_enabled"), "set_enable_follow_smoothing", "is_follow_smoothing_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "smoothing_speed"), "set_follow_smoothing", "get_follow_smoothing");
+ ADD_GROUP("Offset", "offset_");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset_v", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset_h", PROPERTY_HINT_RANGE, "-1,1,0.01"), "set_h_offset", "get_h_offset");
+
ADD_GROUP("Drag Margin", "drag_margin_");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "drag_margin_left", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_LEFT);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "drag_margin_top", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_margin", "get_drag_margin", MARGIN_TOP);
diff --git a/scene/2d/camera_2d.h b/scene/2d/camera_2d.h
index 13b6be3978..99571500bf 100644
--- a/scene/2d/camera_2d.h
+++ b/scene/2d/camera_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CAMERA_2D_H
#define CAMERA_2D_H
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 82123d12ac..27bdeda4a8 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "canvas_item.h"
#include "core/method_bind_ext.gen.inc"
#include "message_queue.h"
@@ -93,6 +94,7 @@ void CanvasItemMaterial::_update_shader() {
case BLEND_MODE_SUB: code += "blend_sub"; break;
case BLEND_MODE_MUL: code += "blend_mul"; break;
case BLEND_MODE_PREMULT_ALPHA: code += "blend_premul_alpha"; break;
+ case BLEND_MODE_DISABLED: code += "blend_disabled"; break;
}
switch (light_mode) {
@@ -100,7 +102,7 @@ void CanvasItemMaterial::_update_shader() {
case LIGHT_MODE_UNSHADED: code += ",unshaded"; break;
case LIGHT_MODE_LIGHT_ONLY: code += ",light_only"; break;
}
- code += ";\n"; //thats it.
+ code += ";\n"; //that's it.
ShaderData shader_data;
shader_data.shader = VS::get_singleton()->shader_create();
@@ -244,6 +246,14 @@ CanvasItemMaterial::~CanvasItemMaterial() {
///////////////////////////////////////////////////////////////////
+bool CanvasItem::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+ if (_edit_use_rect()) {
+ return _edit_get_rect().has_point(p_point);
+ } else {
+ return p_point.length() < p_tolerance;
+ }
+}
+
bool CanvasItem::is_visible_in_tree() const {
if (!is_inside_tree())
@@ -262,7 +272,8 @@ bool CanvasItem::is_visible_in_tree() const {
void CanvasItem::_propagate_visibility_changed(bool p_visible) {
- notification(NOTIFICATION_VISIBILITY_CHANGED);
+ if (!first_draw)
+ notification(NOTIFICATION_VISIBILITY_CHANGED);
if (p_visible)
update(); //todo optimize
@@ -411,7 +422,7 @@ void CanvasItem::_enter_canvas() {
RID canvas;
if (canvas_layer)
- canvas = canvas_layer->get_world_2d()->get_canvas();
+ canvas = canvas_layer->get_canvas();
else
canvas = get_viewport()->find_world_2d()->get_canvas();
@@ -683,7 +694,7 @@ void CanvasItem::draw_texture(const Ref<Texture> &p_texture, const Point2 &p_pos
ERR_FAIL_COND(p_texture.is_null());
- p_texture->draw(canvas_item, p_pos, p_modulate);
+ p_texture->draw(canvas_item, p_pos, p_modulate, false, p_normal_map);
}
void CanvasItem::draw_texture_rect(const Ref<Texture> &p_texture, const Rect2 &p_rect, bool p_tile, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) {
@@ -778,6 +789,22 @@ void CanvasItem::draw_colored_polygon(const Vector<Point2> &p_points, const Colo
VisualServer::get_singleton()->canvas_item_add_polygon(canvas_item, p_points, colors, p_uvs, rid, rid_normal, p_antialiased);
}
+void CanvasItem::draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
+
+ ERR_FAIL_COND(p_mesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+
+ VisualServer::get_singleton()->canvas_item_add_mesh(canvas_item, p_mesh->get_rid(), texture_rid, normal_map_rid);
+}
+void CanvasItem::draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map) {
+
+ ERR_FAIL_COND(p_multimesh.is_null());
+ RID texture_rid = p_texture.is_valid() ? p_texture->get_rid() : RID();
+ RID normal_map_rid = p_normal_map.is_valid() ? p_normal_map->get_rid() : RID();
+ VisualServer::get_singleton()->canvas_item_add_multimesh(canvas_item, p_multimesh->get_rid(), texture_rid, normal_map_rid);
+}
+
void CanvasItem::draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) {
if (!drawing) {
@@ -804,6 +831,12 @@ float CanvasItem::draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const
void CanvasItem::_notify_transform(CanvasItem *p_node) {
+ /* This check exists to avoid re-propagating the transform
+ * notification down the tree on dirty nodes. It provides
+ * optimization by avoiding redundancy (nodes are dirty, will get the
+ * notification anyway).
+ */
+
if (/*p_node->xform_change.in_list() &&*/ p_node->global_invalid) {
return; //nothing to do
}
@@ -837,7 +870,7 @@ RID CanvasItem::get_canvas() const {
ERR_FAIL_COND_V(!is_inside_tree(), RID());
if (canvas_layer)
- return canvas_layer->get_world_2d()->get_canvas();
+ return canvas_layer->get_canvas();
else
return get_viewport()->find_world_2d()->get_canvas();
}
@@ -858,9 +891,7 @@ Ref<World2D> CanvasItem::get_world_2d() const {
CanvasItem *tl = get_toplevel();
- if (tl->canvas_layer) {
- return tl->canvas_layer->get_world_2d();
- } else if (tl->get_viewport()) {
+ if (tl->get_viewport()) {
return tl->get_viewport()->find_world_2d();
} else {
return Ref<World2D>();
@@ -959,7 +990,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("_edit_set_position", "position"), &CanvasItem::_edit_set_position);
ClassDB::bind_method(D_METHOD("_edit_get_position"), &CanvasItem::_edit_get_position);
- ClassDB::bind_method(D_METHOD("_edit_use_position"), &CanvasItem::_edit_use_position);
+ ClassDB::bind_method(D_METHOD("_edit_set_scale", "scale"), &CanvasItem::_edit_set_scale);
+ ClassDB::bind_method(D_METHOD("_edit_get_scale"), &CanvasItem::_edit_get_scale);
ClassDB::bind_method(D_METHOD("_edit_set_rect", "rect"), &CanvasItem::_edit_set_rect);
ClassDB::bind_method(D_METHOD("_edit_get_rect"), &CanvasItem::_edit_get_rect);
ClassDB::bind_method(D_METHOD("_edit_use_rect"), &CanvasItem::_edit_use_rect);
@@ -1015,6 +1047,8 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture", "normal_map", "antialiased"), &CanvasItem::draw_colored_polygon, DEFVAL(PoolVector2Array()), DEFVAL(Variant()), DEFVAL(Variant()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("draw_string", "font", "position", "text", "modulate", "clip_w"), &CanvasItem::draw_string, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("draw_char", "font", "position", "char", "next", "modulate"), &CanvasItem::draw_char, DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("draw_mesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()));
+ ClassDB::bind_method(D_METHOD("draw_multimesh", "mesh", "texture", "normal_map"), &CanvasItem::draw_mesh, DEFVAL(Ref<Texture>()));
ClassDB::bind_method(D_METHOD("draw_set_transform", "position", "rotation", "scale"), &CanvasItem::draw_set_transform);
ClassDB::bind_method(D_METHOD("draw_set_transform_matrix", "xform"), &CanvasItem::draw_set_transform_matrix);
@@ -1058,9 +1092,9 @@ void CanvasItem::_bind_methods() {
ADD_GROUP("Material", "");
ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial"), "set_material", "get_material");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "use_parent_material"), "set_use_parent_material", "get_use_parent_material");
- //exporting these two things doesn't really make much sense i think
- //ADD_PROPERTY( PropertyInfo(Variant::BOOL,"transform/toplevel"), "set_as_toplevel","is_set_as_toplevel") ;
- //ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
+ //exporting these things doesn't really make much sense i think
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toplevel", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_as_toplevel", "is_set_as_toplevel");
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL,"transform/notify"),"set_transform_notify","is_transform_notify_enabled");
ADD_SIGNAL(MethodInfo("draw"));
ADD_SIGNAL(MethodInfo("visibility_changed"));
@@ -1072,6 +1106,7 @@ void CanvasItem::_bind_methods() {
BIND_ENUM_CONSTANT(BLEND_MODE_SUB);
BIND_ENUM_CONSTANT(BLEND_MODE_MUL);
BIND_ENUM_CONSTANT(BLEND_MODE_PREMULT_ALPHA);
+ BIND_ENUM_CONSTANT(BLEND_MODE_DISABLED);
BIND_CONSTANT(NOTIFICATION_TRANSFORM_CHANGED);
BIND_CONSTANT(NOTIFICATION_DRAW);
diff --git a/scene/2d/canvas_item.h b/scene/2d/canvas_item.h
index 2384c0f370..10d5082dfc 100644
--- a/scene/2d/canvas_item.h
+++ b/scene/2d/canvas_item.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,12 +27,14 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CANVAS_ITEM_H
#define CANVAS_ITEM_H
#include "scene/main/node.h"
#include "scene/main/scene_tree.h"
#include "scene/resources/material.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/shader.h"
#include "scene/resources/texture.h"
@@ -52,7 +54,8 @@ public:
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
- BLEND_MODE_PREMULT_ALPHA
+ BLEND_MODE_PREMULT_ALPHA,
+ BLEND_MODE_DISABLED
};
enum LightMode {
@@ -143,7 +146,8 @@ public:
BLEND_MODE_ADD,
BLEND_MODE_SUB,
BLEND_MODE_MUL,
- BLEND_MODE_PREMULT_ALPHA
+ BLEND_MODE_PREMULT_ALPHA,
+ BLEND_MODE_DISABLED
};
private:
@@ -218,29 +222,46 @@ public:
/* EDITOR */
+ // Save and restore a CanvasItem state
virtual void _edit_set_state(const Dictionary &p_state){};
virtual Dictionary _edit_get_state() const { return Dictionary(); };
- // Used to move/select the node
- virtual void _edit_set_position(const Point2 &p_position){};
- virtual Point2 _edit_get_position() const { return Point2(); };
- virtual bool _edit_use_position() const { return false; };
+ // Used to move the node
+ virtual void _edit_set_position(const Point2 &p_position) = 0;
+ virtual Point2 _edit_get_position() const = 0;
+
+ // Used to scale the node
+ virtual void _edit_set_scale(const Size2 &p_scale) = 0;
+ virtual Size2 _edit_get_scale() const = 0;
- // Used to resize/move/select the node
+ // Used to resize/move the node
virtual void _edit_set_rect(const Rect2 &p_rect){};
- virtual Rect2 _edit_get_rect() const { return Rect2(-32, -32, 64, 64); };
- Rect2 _edit_get_item_and_children_rect() const;
+ virtual Rect2 _edit_get_rect() const { return Rect2(0, 0, 0, 0); };
virtual bool _edit_use_rect() const { return false; };
+ Rect2 _edit_get_item_and_children_rect() const;
+
+ // used to select the node
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
// Used to rotate the node
- virtual void _edit_set_rotation(float p_rotation){};
- virtual float _edit_get_rotation() const { return 0.0; };
- virtual bool _edit_use_rotation() const { return false; };
+ virtual void
+ _edit_set_rotation(float p_rotation){};
+ virtual float _edit_get_rotation() const {
+ return 0.0;
+ };
+ virtual bool _edit_use_rotation() const {
+ return false;
+ };
// Used to set a pivot
virtual void _edit_set_pivot(const Point2 &p_pivot){};
- virtual Point2 _edit_get_pivot() const { return Point2(); };
- virtual bool _edit_use_pivot() const { return false; };
+ virtual Point2 _edit_get_pivot() const {
+ return Point2();
+ };
+ virtual bool _edit_use_pivot() const {
+ return false;
+ };
virtual Size2 _edit_get_minimum_size() const;
@@ -280,6 +301,9 @@ public:
void draw_polygon(const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
void draw_colored_polygon(const Vector<Point2> &p_points, const Color &p_color, const Vector<Point2> &p_uvs = Vector<Point2>(), Ref<Texture> p_texture = Ref<Texture>(), const Ref<Texture> &p_normal_map = Ref<Texture>(), bool p_antialiased = false);
+ void draw_mesh(const Ref<Mesh> &p_mesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
+ void draw_multimesh(const Ref<MultiMesh> &p_multimesh, const Ref<Texture> &p_texture, const Ref<Texture> &p_normal_map);
+
void draw_string(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1);
float draw_char(const Ref<Font> &p_font, const Point2 &p_pos, const String &p_char, const String &p_next = "", const Color &p_modulate = Color(1, 1, 1));
@@ -302,7 +326,9 @@ public:
virtual Transform2D get_global_transform_with_canvas() const;
CanvasItem *get_toplevel() const;
- _FORCE_INLINE_ RID get_canvas_item() const { return canvas_item; }
+ _FORCE_INLINE_ RID get_canvas_item() const {
+ return canvas_item;
+ }
void set_block_transform_notify(bool p_enable);
bool is_block_transform_notify_enabled() const;
diff --git a/scene/2d/canvas_modulate.cpp b/scene/2d/canvas_modulate.cpp
index 05831609fc..2f8568ccbf 100644
--- a/scene/2d/canvas_modulate.cpp
+++ b/scene/2d/canvas_modulate.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "canvas_modulate.h"
void CanvasModulate::_notification(int p_what) {
diff --git a/scene/2d/canvas_modulate.h b/scene/2d/canvas_modulate.h
index 4195c1386c..888ed95f6b 100644
--- a/scene/2d/canvas_modulate.h
+++ b/scene/2d/canvas_modulate.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CANVASMODULATE_H
#define CANVASMODULATE_H
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 73e5dc6021..d05c818ae1 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "collision_object_2d.h"
#include "scene/scene_string_names.h"
#include "servers/physics_2d_server.h"
@@ -327,6 +328,20 @@ void CollisionObject2D::_update_pickable() {
Physics2DServer::get_singleton()->body_set_pickable(rid, pickable);
}
+String CollisionObject2D::get_configuration_warning() const {
+
+ String warning = Node2D::get_configuration_warning();
+
+ if (shapes.empty()) {
+ if (warning == String()) {
+ warning += "\n";
+ }
+ warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape2D or CollisionPolygon2D as a child to define its shape.");
+ }
+
+ return warning;
+}
+
void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_rid"), &CollisionObject2D::get_rid);
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index a828d8d8ea..6da63d1a0b 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLLISION_OBJECT_2D_H
#define COLLISION_OBJECT_2D_H
@@ -106,6 +107,8 @@ public:
void set_pickable(bool p_enabled);
bool is_pickable() const;
+ String get_configuration_warning() const;
+
_FORCE_INLINE_ RID get_rid() const { return rid; }
CollisionObject2D();
diff --git a/scene/2d/collision_polygon_2d.cpp b/scene/2d/collision_polygon_2d.cpp
index 92855299ae..9d2a83fda7 100644
--- a/scene/2d/collision_polygon_2d.cpp
+++ b/scene/2d/collision_polygon_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "collision_polygon_2d.h"
#include "collision_object_2d.h"
@@ -114,6 +115,15 @@ Vector<Vector<Vector2> > CollisionPolygon2D::_decompose_in_convex() {
return decomp;
}
+void CollisionPolygon2D::_update_in_shape_owner(bool p_xform_only) {
+
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ if (p_xform_only)
+ return;
+ parent->shape_owner_set_disabled(owner_id, disabled);
+ parent->shape_owner_set_one_way_collision(owner_id, one_way_collision);
+}
+
void CollisionPolygon2D::_notification(int p_what) {
switch (p_what) {
@@ -123,22 +133,27 @@ void CollisionPolygon2D::_notification(int p_what) {
if (parent) {
owner_id = parent->create_shape_owner(this);
_build_polygon();
- parent->shape_owner_set_transform(owner_id, get_transform());
- parent->shape_owner_set_disabled(owner_id, disabled);
- parent->shape_owner_set_one_way_collision(owner_id, one_way_collision);
+ _update_in_shape_owner();
}
/*if (Engine::get_singleton()->is_editor_hint()) {
//display above all else
set_z_as_relative(false);
- set_z(VS::CANVAS_ITEM_Z_MAX - 1);
+ set_z_index(VS::CANVAS_ITEM_Z_MAX - 1);
}*/
} break;
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (parent) {
+ _update_in_shape_owner();
+ }
+
+ } break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
- parent->shape_owner_set_transform(owner_id, get_transform());
+ _update_in_shape_owner(true);
}
} break;
@@ -160,7 +175,8 @@ void CollisionPolygon2D::_notification(int p_what) {
Vector2 p = polygon[i];
Vector2 n = polygon[(i + 1) % polygon.size()];
- draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 3);
+ // draw line with width <= 1, so it does not scale with zoom and break pixel exact editing
+ draw_line(p, n, Color(0.9, 0.2, 0.0, 0.8), 1);
}
#define DEBUG_DECOMPOSE
#if defined(TOOLS_ENABLED) && defined(DEBUG_DECOMPOSE)
@@ -248,6 +264,15 @@ Rect2 CollisionPolygon2D::_edit_get_rect() const {
return aabb;
}
+bool CollisionPolygon2D::_edit_use_rect() const {
+ return true;
+}
+
+bool CollisionPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, Variant(polygon));
+}
+
String CollisionPolygon2D::get_configuration_warning() const {
if (!Object::cast_to<CollisionObject2D>(get_parent())) {
diff --git a/scene/2d/collision_polygon_2d.h b/scene/2d/collision_polygon_2d.h
index 2fb08a4599..412a923292 100644
--- a/scene/2d/collision_polygon_2d.h
+++ b/scene/2d/collision_polygon_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLLISION_POLYGON_2D_H
#define COLLISION_POLYGON_2D_H
@@ -58,6 +59,8 @@ protected:
void _build_polygon();
+ void _update_in_shape_owner(bool p_xform_only = false);
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -70,6 +73,8 @@ public:
Vector<Point2> get_polygon() const;
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
virtual String get_configuration_warning() const;
diff --git a/scene/2d/collision_shape_2d.cpp b/scene/2d/collision_shape_2d.cpp
index f7cb5473e3..83ef4df8f4 100644
--- a/scene/2d/collision_shape_2d.cpp
+++ b/scene/2d/collision_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "collision_shape_2d.h"
#include "collision_object_2d.h"
@@ -44,6 +45,15 @@ void CollisionShape2D::_shape_changed() {
update();
}
+void CollisionShape2D::_update_in_shape_owner(bool p_xform_only) {
+
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ if (p_xform_only)
+ return;
+ parent->shape_owner_set_disabled(owner_id, disabled);
+ parent->shape_owner_set_one_way_collision(owner_id, one_way_collision);
+}
+
void CollisionShape2D::_notification(int p_what) {
switch (p_what) {
@@ -56,22 +66,27 @@ void CollisionShape2D::_notification(int p_what) {
if (shape.is_valid()) {
parent->shape_owner_add_shape(owner_id, shape);
}
- parent->shape_owner_set_transform(owner_id, get_transform());
- parent->shape_owner_set_disabled(owner_id, disabled);
- parent->shape_owner_set_one_way_collision(owner_id, one_way_collision);
+ _update_in_shape_owner();
}
/*if (Engine::get_singleton()->is_editor_hint()) {
//display above all else
set_z_as_relative(false);
- set_z(VS::CANVAS_ITEM_Z_MAX - 1);
+ set_z_index(VS::CANVAS_ITEM_Z_MAX - 1);
}*/
} break;
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (parent) {
+ _update_in_shape_owner();
+ }
+
+ } break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
- parent->shape_owner_set_transform(owner_id, get_transform());
+ _update_in_shape_owner(true);
}
} break;
@@ -158,9 +173,12 @@ Ref<Shape2D> CollisionShape2D::get_shape() const {
return shape;
}
-Rect2 CollisionShape2D::_edit_get_rect() const {
+bool CollisionShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (!shape.is_valid())
+ return false;
- return rect;
+ return shape->_edit_is_selected_on_click(p_point, p_tolerance);
}
String CollisionShape2D::get_configuration_warning() const {
diff --git a/scene/2d/collision_shape_2d.h b/scene/2d/collision_shape_2d.h
index 4745c659c8..ed2c09d53d 100644
--- a/scene/2d/collision_shape_2d.h
+++ b/scene/2d/collision_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLLISION_SHAPE_2D_H
#define COLLISION_SHAPE_2D_H
@@ -46,12 +47,14 @@ class CollisionShape2D : public Node2D {
bool disabled;
bool one_way_collision;
+ void _update_in_shape_owner(bool p_xform_only = false);
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
- virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
void set_shape(const Ref<Shape2D> &p_shape);
Ref<Shape2D> get_shape() const;
diff --git a/scene/2d/joints_2d.cpp b/scene/2d/joints_2d.cpp
index b98cdcc365..329382c034 100644
--- a/scene/2d/joints_2d.cpp
+++ b/scene/2d/joints_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "joints_2d.h"
#include "engine.h"
@@ -74,8 +75,7 @@ void Joint2D::_update_joint(bool p_only_free) {
ba = body_a->get_rid();
bb = body_b->get_rid();
- if (exclude_from_collision)
- Physics2DServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
+ Physics2DServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
}
void Joint2D::set_node_a(const NodePath &p_node_a) {
diff --git a/scene/2d/joints_2d.h b/scene/2d/joints_2d.h
index a6292be51c..744994f0a7 100644
--- a/scene/2d/joints_2d.h
+++ b/scene/2d/joints_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef JOINTS_2D_H
#define JOINTS_2D_H
diff --git a/scene/2d/light_2d.cpp b/scene/2d/light_2d.cpp
index d2b987e037..9a44eb31bb 100644
--- a/scene/2d/light_2d.cpp
+++ b/scene/2d/light_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,40 +27,46 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "light_2d.h"
#include "engine.h"
#include "servers/visual_server.h"
-void Light2D::_edit_set_pivot(const Point2 &p_pivot) {
+Dictionary Light2D::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["offset"] = get_texture_offset();
+ return state;
+}
- set_texture_offset(p_pivot);
+void Light2D::_edit_set_state(const Dictionary &p_state) {
+ Node2D::_edit_set_state(p_state);
+ set_texture_offset(p_state["offset"]);
}
-Point2 Light2D::_edit_get_pivot() const {
+void Light2D::_edit_set_pivot(const Point2 &p_pivot) {
+ set_position(get_transform().xform(p_pivot));
+ set_texture_offset(get_texture_offset() - p_pivot);
+}
- return get_texture_offset();
+Point2 Light2D::_edit_get_pivot() const {
+ return Vector2();
}
-bool Light2D::_edit_use_pivot() const {
+bool Light2D::_edit_use_pivot() const {
return true;
}
Rect2 Light2D::_edit_get_rect() const {
-
if (texture.is_null())
- return Rect2(0, 0, 1, 1);
-
- Size2i s;
+ return Node2D::_edit_get_rect();
- s = texture->get_size() * _scale;
- Point2i ofs = texture_offset;
- ofs -= s / 2;
-
- if (s == Size2(0, 0))
- s = Size2(1, 1);
+ Size2 s = texture->get_size() * _scale;
+ return Rect2(texture_offset - s / 2.0, s);
+}
- return Rect2(ofs, s);
+bool Light2D::_edit_use_rect() const {
+ return true;
}
void Light2D::_update_light_visibility() {
@@ -130,6 +136,7 @@ void Light2D::set_texture_offset(const Vector2 &p_offset) {
texture_offset = p_offset;
VS::get_singleton()->canvas_light_set_texture_offset(canvas_light, texture_offset);
item_rect_changed();
+ _change_notify("offset");
}
Vector2 Light2D::get_texture_offset() const {
diff --git a/scene/2d/light_2d.h b/scene/2d/light_2d.h
index 9b9da8379f..543805e329 100644
--- a/scene/2d/light_2d.h
+++ b/scene/2d/light_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LIGHT_2D_H
#define LIGHT_2D_H
@@ -84,10 +85,14 @@ protected:
static void _bind_methods();
public:
+ virtual Dictionary _edit_get_state() const;
+ virtual void _edit_set_state(const Dictionary &p_state);
+
virtual void _edit_set_pivot(const Point2 &p_pivot);
virtual Point2 _edit_get_pivot() const;
virtual bool _edit_use_pivot() const;
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/light_occluder_2d.cpp b/scene/2d/light_occluder_2d.cpp
index 92e0d8a2f6..c9e5d0f1bc 100644
--- a/scene/2d/light_occluder_2d.cpp
+++ b/scene/2d/light_occluder_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "light_occluder_2d.h"
#include "engine.h"
@@ -106,12 +107,12 @@ OccluderPolygon2D::~OccluderPolygon2D() {
VS::get_singleton()->free(occ_polygon);
}
-#ifdef DEBUG_ENABLED
void LightOccluder2D::_poly_changed() {
+#ifdef DEBUG_ENABLED
update();
-}
#endif
+}
void LightOccluder2D::_notification(int p_what) {
@@ -220,9 +221,7 @@ void LightOccluder2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_occluder_light_mask", "mask"), &LightOccluder2D::set_occluder_light_mask);
ClassDB::bind_method(D_METHOD("get_occluder_light_mask"), &LightOccluder2D::get_occluder_light_mask);
-#ifdef DEBUG_ENABLED
ClassDB::bind_method("_poly_changed", &LightOccluder2D::_poly_changed);
-#endif
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"), "set_occluder_polygon", "get_occluder_polygon");
ADD_PROPERTY(PropertyInfo(Variant::INT, "light_mask", PROPERTY_HINT_LAYERS_2D_RENDER), "set_occluder_light_mask", "get_occluder_light_mask");
diff --git a/scene/2d/light_occluder_2d.h b/scene/2d/light_occluder_2d.h
index cca7bfecd6..d59c9100b0 100644
--- a/scene/2d/light_occluder_2d.h
+++ b/scene/2d/light_occluder_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LIGHTOCCLUDER2D_H
#define LIGHTOCCLUDER2D_H
@@ -77,9 +78,7 @@ class LightOccluder2D : public Node2D {
int mask;
Ref<OccluderPolygon2D> occluder_polygon;
-#ifdef DEBUG_ENABLED
void _poly_changed();
-#endif
protected:
void _notification(int p_what);
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 57a0e15447..3e61dd05f4 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "line_2d.h"
#include "line_builder.h"
@@ -48,6 +49,36 @@ Line2D::Line2D() :
_round_precision = 8;
}
+Rect2 Line2D::_edit_get_rect() const {
+
+ if (_points.size() == 0)
+ return Rect2(0, 0, 0, 0);
+ Vector2 d = Vector2(_width, _width);
+ Rect2 aabb = Rect2(_points[0] - d, 2 * d);
+ for (int i = 1; i < _points.size(); i++) {
+ aabb.expand_to(_points[i] - d);
+ aabb.expand_to(_points[i] + d);
+ }
+ return aabb;
+}
+
+bool Line2D::_edit_use_rect() const {
+ return true;
+}
+
+bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ const real_t d = _width / 2 + p_tolerance;
+ PoolVector<Vector2>::Read points = _points.read();
+ for (int i = 0; i < _points.size() - 1; i++) {
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, &points[i]);
+ if (p.distance_to(p_point) <= d)
+ return true;
+ }
+
+ return false;
+}
+
void Line2D::set_points(const PoolVector<Vector2> &p_points) {
_points = p_points;
update();
@@ -225,18 +256,22 @@ void Line2D::_draw() {
lb.sharp_limit = _sharp_limit;
lb.width = _width;
- lb.build();
-
RID texture_rid;
- if (_texture.is_valid())
+ if (_texture.is_valid()) {
texture_rid = (**_texture).get_rid();
+ lb.tile_aspect = _texture->get_size().aspect();
+ }
+
+ lb.build();
+
VS::get_singleton()->canvas_item_add_triangle_array(
get_canvas_item(),
lb.indices,
lb.vertices,
lb.colors,
- lb.uvs,
+ lb.uvs, Vector<int>(), Vector<float>(),
+
texture_rid);
// DEBUG
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index 6426484f02..24c48982cd 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LINE2D_H
#define LINE2D_H
@@ -57,6 +58,10 @@ public:
Line2D();
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_points(const PoolVector<Vector2> &p_points);
PoolVector<Vector2> get_points() const;
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 4873c47827..845788bada 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "line_builder.h"
//----------------------------------------------------------------------------
@@ -100,6 +101,7 @@ LineBuilder::LineBuilder() {
round_precision = 8;
begin_cap_mode = Line2D::LINE_CAP_NONE;
end_cap_mode = Line2D::LINE_CAP_NONE;
+ tile_aspect = 1.f;
_interpolate_color = false;
_last_index[0] = 0;
@@ -110,6 +112,7 @@ void LineBuilder::clear_output() {
vertices.clear();
colors.clear();
indices.clear();
+ uvs.clear();
}
void LineBuilder::build() {
@@ -120,6 +123,8 @@ void LineBuilder::build() {
return;
}
+ ERR_FAIL_COND(tile_aspect <= 0.f);
+
const float hw = width / 2.f;
const float hw_sq = hw * hw;
const float sharp_limit_sq = sharp_limit * sharp_limit;
@@ -163,7 +168,7 @@ void LineBuilder::build() {
current_distance1 = current_distance0;
} else if (begin_cap_mode == Line2D::LINE_CAP_ROUND) {
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx0 = 0.5f;
+ uvx0 = 0.5f / tile_aspect;
}
new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, 1.f, 1.f));
total_distance += width;
@@ -285,8 +290,8 @@ void LineBuilder::build() {
color1 = gradient->get_color_at_offset(current_distance1 / total_distance);
}
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx0 = current_distance0 / width;
- uvx1 = current_distance1 / width;
+ uvx0 = current_distance0 / (width * tile_aspect);
+ uvx1 = current_distance1 / (width * tile_aspect);
}
strip_add_quad(pos_up1, pos_down1, color1, uvx1);
@@ -346,7 +351,7 @@ void LineBuilder::build() {
}
if (intersection_result != SEGMENT_INTERSECT)
- // In this case the joint is too fucked up to be re-used,
+ // In this case the joint is too corrputed to be re-used,
// start again the strip with fallback points
strip_begin(pos_up0, pos_down0, color1, uvx1);
}
@@ -372,7 +377,7 @@ void LineBuilder::build() {
color1 = gradient->get_color(gradient->get_points_count() - 1);
}
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx1 = current_distance1 / width;
+ uvx1 = current_distance1 / (width * tile_aspect);
}
strip_add_quad(pos_up1, pos_down1, color1, uvx1);
diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h
index f12fbf6f82..b1c62f84e2 100644
--- a/scene/2d/line_builder.h
+++ b/scene/2d/line_builder.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LINE_BUILDER_H
#define LINE_BUILDER_H
@@ -49,6 +50,7 @@ public:
Line2D::LineTextureMode texture_mode;
float sharp_limit;
int round_precision;
+ float tile_aspect; // w/h
// TODO offset_joints option (offers alternative implementation of round joints)
// TODO Move in a struct and reference it
diff --git a/scene/2d/mesh_instance_2d.cpp b/scene/2d/mesh_instance_2d.cpp
new file mode 100644
index 0000000000..9f21fe1a1f
--- /dev/null
+++ b/scene/2d/mesh_instance_2d.cpp
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* mesh_instance_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "mesh_instance_2d.h"
+
+void MeshInstance2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_DRAW) {
+ if (mesh.is_valid()) {
+ draw_mesh(mesh, texture, normal_map);
+ }
+ }
+}
+
+void MeshInstance2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_mesh", "mesh"), &MeshInstance2D::set_mesh);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &MeshInstance2D::get_mesh);
+
+ ClassDB::bind_method(D_METHOD("set_texture", "texture"), &MeshInstance2D::set_texture);
+ ClassDB::bind_method(D_METHOD("get_texture"), &MeshInstance2D::get_texture);
+
+ ClassDB::bind_method(D_METHOD("set_normal_map", "normal_map"), &MeshInstance2D::set_normal_map);
+ ClassDB::bind_method(D_METHOD("get_normal_map"), &MeshInstance2D::get_normal_map);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_texture", "get_texture");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "normal_map", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_normal_map", "get_normal_map");
+}
+
+void MeshInstance2D::set_mesh(const Ref<Mesh> &p_mesh) {
+
+ mesh = p_mesh;
+ update();
+}
+
+Ref<Mesh> MeshInstance2D::get_mesh() const {
+
+ return mesh;
+}
+
+void MeshInstance2D::set_texture(const Ref<Texture> &p_texture) {
+
+ if (p_texture == texture)
+ return;
+ texture = p_texture;
+ update();
+ emit_signal("texture_changed");
+ _change_notify("texture");
+}
+
+void MeshInstance2D::set_normal_map(const Ref<Texture> &p_texture) {
+
+ normal_map = p_texture;
+ update();
+}
+
+Ref<Texture> MeshInstance2D::get_normal_map() const {
+
+ return normal_map;
+}
+
+Ref<Texture> MeshInstance2D::get_texture() const {
+
+ return texture;
+}
+
+Rect2 MeshInstance2D::_edit_get_rect() const {
+
+ if (mesh.is_valid()) {
+ AABB aabb = mesh->get_aabb();
+ return Rect2(aabb.position.x, aabb.position.y, aabb.size.x, aabb.size.y);
+ }
+
+ return Node2D::_edit_get_rect();
+}
+
+MeshInstance2D::MeshInstance2D() {
+}
diff --git a/scene/2d/mesh_instance_2d.h b/scene/2d/mesh_instance_2d.h
new file mode 100644
index 0000000000..c9889c1c03
--- /dev/null
+++ b/scene/2d/mesh_instance_2d.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* mesh_instance_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 MESH_INSTANCE_2D_H
+#define MESH_INSTANCE_2D_H
+
+#include "scene/2d/node_2d.h"
+
+class MeshInstance2D : public Node2D {
+ GDCLASS(MeshInstance2D, Node2D)
+
+ Ref<Mesh> mesh;
+
+ Ref<Texture> texture;
+ Ref<Texture> normal_map;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
+
+ void set_texture(const Ref<Texture> &p_texture);
+ Ref<Texture> get_texture() const;
+
+ void set_normal_map(const Ref<Texture> &p_texture);
+ Ref<Texture> get_normal_map() const;
+
+ virtual Rect2 _edit_get_rect() const;
+
+ MeshInstance2D();
+};
+
+#endif // MESH_INSTANCE_2D_H
diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp
index 9eff107827..16e0386952 100644
--- a/scene/2d/navigation2d.cpp
+++ b/scene/2d/navigation2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "navigation2d.h"
#define USE_ENTRY_POINT
@@ -205,7 +206,7 @@ void Navigation2D::_navpoly_unlink(int p_id) {
nm.linked = false;
}
-int Navigation2D::navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) {
+int Navigation2D::navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner) {
int id = last_id++;
NavMesh nm;
@@ -670,7 +671,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) {
if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) {
- E->get().owner;
+ return E->get().owner;
}
}
}
@@ -708,7 +709,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) {
void Navigation2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("navpoly_create", "mesh", "xform", "owner"), &Navigation2D::navpoly_create, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("navpoly_add", "mesh", "xform", "owner"), &Navigation2D::navpoly_add, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("navpoly_set_transform", "id", "xform"), &Navigation2D::navpoly_set_transform);
ClassDB::bind_method(D_METHOD("navpoly_remove", "id"), &Navigation2D::navpoly_remove);
diff --git a/scene/2d/navigation2d.h b/scene/2d/navigation2d.h
index bb97e1a9a9..02c46d5de1 100644
--- a/scene/2d/navigation2d.h
+++ b/scene/2d/navigation2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NAVIGATION_2D_H
#define NAVIGATION_2D_H
@@ -159,7 +160,7 @@ protected:
public:
//API should be as dynamic as possible
- int navpoly_create(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL);
+ int navpoly_add(const Ref<NavigationPolygon> &p_mesh, const Transform2D &p_xform, Object *p_owner = NULL);
void navpoly_set_transform(int p_id, const Transform2D &p_xform);
void navpoly_remove(int p_id);
diff --git a/scene/2d/navigation_polygon.cpp b/scene/2d/navigation_polygon.cpp
index c53241e985..6e27bf1c1d 100644
--- a/scene/2d/navigation_polygon.cpp
+++ b/scene/2d/navigation_polygon.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "navigation_polygon.h"
#include "core_string_names.h"
@@ -35,9 +36,50 @@
#include "thirdparty/misc/triangulator.h"
+Rect2 NavigationPolygon::_edit_get_rect() const {
+
+ if (rect_cache_dirty) {
+ item_rect = Rect2();
+ bool first = true;
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const PoolVector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ PoolVector<Vector2>::Read p = outline.read();
+ for (int j = 0; j < outline_size; j++) {
+ if (first) {
+ item_rect = Rect2(p[j], Vector2(0, 0));
+ first = false;
+ } else {
+ item_rect.expand_to(p[j]);
+ }
+ }
+ }
+
+ rect_cache_dirty = false;
+ }
+ return item_rect;
+}
+
+bool NavigationPolygon::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < outlines.size(); i++) {
+ const PoolVector<Vector2> &outline = outlines[i];
+ const int outline_size = outline.size();
+ if (outline_size < 3)
+ continue;
+ if (Geometry::is_point_in_polygon(p_point, Variant(outline)))
+ return true;
+ }
+ return false;
+}
+
void NavigationPolygon::set_vertices(const PoolVector<Vector2> &p_vertices) {
vertices = p_vertices;
+ rect_cache_dirty = true;
}
PoolVector<Vector2> NavigationPolygon::get_vertices() const {
@@ -70,6 +112,7 @@ void NavigationPolygon::_set_outlines(const Array &p_array) {
for (int i = 0; i < p_array.size(); i++) {
outlines[i] = p_array[i];
}
+ rect_cache_dirty = true;
}
Array NavigationPolygon::_get_outlines() const {
@@ -93,6 +136,7 @@ void NavigationPolygon::add_polygon(const Vector<int> &p_polygon) {
void NavigationPolygon::add_outline_at_index(const PoolVector<Vector2> &p_outline, int p_index) {
outlines.insert(p_index, p_outline);
+ rect_cache_dirty = true;
}
int NavigationPolygon::get_polygon_count() const {
@@ -112,6 +156,7 @@ void NavigationPolygon::clear_polygons() {
void NavigationPolygon::add_outline(const PoolVector<Vector2> &p_outline) {
outlines.push_back(p_outline);
+ rect_cache_dirty = true;
}
int NavigationPolygon::get_outline_count() const {
@@ -122,12 +167,14 @@ int NavigationPolygon::get_outline_count() const {
void NavigationPolygon::set_outline(int p_idx, const PoolVector<Vector2> &p_outline) {
ERR_FAIL_INDEX(p_idx, outlines.size());
outlines[p_idx] = p_outline;
+ rect_cache_dirty = true;
}
void NavigationPolygon::remove_outline(int p_idx) {
ERR_FAIL_INDEX(p_idx, outlines.size());
outlines.remove(p_idx);
+ rect_cache_dirty = true;
}
PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
@@ -138,6 +185,7 @@ PoolVector<Vector2> NavigationPolygon::get_outline(int p_idx) const {
void NavigationPolygon::clear_outlines() {
outlines.clear();
+ rect_cache_dirty = true;
}
void NavigationPolygon::make_polygons_from_outlines() {
@@ -264,12 +312,13 @@ void NavigationPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_outlines", "outlines"), &NavigationPolygon::_set_outlines);
ClassDB::bind_method(D_METHOD("_get_outlines"), &NavigationPolygon::_get_outlines);
- ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_polygons", "_get_polygons");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_outlines", "_get_outlines");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "outlines", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_outlines", "_get_outlines");
}
-NavigationPolygon::NavigationPolygon() {
+NavigationPolygon::NavigationPolygon() :
+ rect_cache_dirty(true) {
}
void NavigationPolygonInstance::set_enabled(bool p_enabled) {
@@ -293,7 +342,7 @@ void NavigationPolygonInstance::set_enabled(bool p_enabled) {
if (navpoly.is_valid()) {
- nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this);
+ nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this);
}
}
}
@@ -311,6 +360,16 @@ bool NavigationPolygonInstance::is_enabled() const {
/////////////////////////////
+Rect2 NavigationPolygonInstance::_edit_get_rect() const {
+
+ return navpoly.is_valid() ? navpoly->_edit_get_rect() : Rect2();
+}
+
+bool NavigationPolygonInstance::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return navpoly.is_valid() ? navpoly->_edit_is_selected_on_click(p_point, p_tolerance) : false;
+}
+
void NavigationPolygonInstance::_notification(int p_what) {
switch (p_what) {
@@ -324,7 +383,7 @@ void NavigationPolygonInstance::_notification(int p_what) {
if (enabled && navpoly.is_valid()) {
- nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this);
+ nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this);
}
break;
}
@@ -419,7 +478,7 @@ void NavigationPolygonInstance::set_navigation_polygon(const Ref<NavigationPolyg
}
if (navigation && navpoly.is_valid() && enabled) {
- nav_id = navigation->navpoly_create(navpoly, get_relative_transform_to_parent(navigation), this);
+ nav_id = navigation->navpoly_add(navpoly, get_relative_transform_to_parent(navigation), this);
}
//update_gizmo();
_change_notify("navpoly");
diff --git a/scene/2d/navigation_polygon.h b/scene/2d/navigation_polygon.h
index 5576a3abd2..d7684c2d94 100644
--- a/scene/2d/navigation_polygon.h
+++ b/scene/2d/navigation_polygon.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NAVIGATION_POLYGON_H
#define NAVIGATION_POLYGON_H
@@ -43,6 +44,9 @@ class NavigationPolygon : public Resource {
Vector<Polygon> polygons;
Vector<PoolVector<Vector2> > outlines;
+ mutable Rect2 item_rect;
+ mutable bool rect_cache_dirty;
+
protected:
static void _bind_methods();
@@ -53,6 +57,9 @@ protected:
Array _get_outlines() const;
public:
+ Rect2 _edit_get_rect() const;
+ bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_vertices(const PoolVector<Vector2> &p_vertices);
PoolVector<Vector2> get_vertices() const;
@@ -93,6 +100,9 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_enabled(bool p_enabled);
bool is_enabled() const;
diff --git a/scene/2d/node_2d.cpp b/scene/2d/node_2d.cpp
index 45f780e50e..3813bd96fe 100644
--- a/scene/2d/node_2d.cpp
+++ b/scene/2d/node_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "node_2d.h"
#include "message_queue.h"
@@ -45,10 +46,9 @@ Dictionary Node2D::_edit_get_state() const {
}
void Node2D::_edit_set_state(const Dictionary &p_state) {
- Dictionary state = p_state;
- pos = state["position"];
- angle = state["rotation"];
- _scale = state["scale"];
+ pos = p_state["position"];
+ angle = p_state["rotation"];
+ _scale = p_state["scale"];
_update_transform();
_change_notify("rotation");
@@ -58,14 +58,39 @@ void Node2D::_edit_set_state(const Dictionary &p_state) {
}
void Node2D::_edit_set_position(const Point2 &p_position) {
- pos = p_position;
+ set_position(p_position);
}
Point2 Node2D::_edit_get_position() const {
return pos;
}
+void Node2D::_edit_set_scale(const Size2 &p_scale) {
+ set_scale(p_scale);
+}
+
+Size2 Node2D::_edit_get_scale() const {
+ return _scale;
+}
+
+void Node2D::_edit_set_rotation(float p_rotation) {
+ angle = p_rotation;
+ _update_transform();
+ _change_notify("rotation");
+ _change_notify("rotation_degrees");
+}
+
+float Node2D::_edit_get_rotation() const {
+ return angle;
+}
+
+bool Node2D::_edit_use_rotation() const {
+ return true;
+}
+
void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
+ ERR_FAIL_COND(!_edit_use_rect());
+
Rect2 r = _edit_get_rect();
Vector2 zero_offset;
@@ -81,7 +106,7 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
if (r.size.y != 0)
new_scale.y = p_edit_rect.size.y / r.size.y;
- Point2 new_pos = p_edit_rect.position + p_edit_rect.size * zero_offset; //p_edit_rect.pos - r.pos;
+ Point2 new_pos = p_edit_rect.position + p_edit_rect.size * zero_offset;
Transform2D postxf;
postxf.set_rotation_and_scale(angle, _scale);
@@ -95,25 +120,6 @@ void Node2D::_edit_set_rect(const Rect2 &p_edit_rect) {
_change_notify("position");
}
-bool Node2D::_edit_use_rect() const {
- return true;
-}
-
-void Node2D::_edit_set_rotation(float p_rotation) {
- angle = p_rotation;
- _update_transform();
- _change_notify("rotation");
- _change_notify("rotation_degrees");
-}
-
-float Node2D::_edit_get_rotation() const {
- return angle;
-}
-
-bool Node2D::_edit_use_rotation() const {
- return true;
-}
-
void Node2D::_update_xform_values() {
pos = _mat.elements[2];
@@ -329,13 +335,13 @@ void Node2D::set_global_transform(const Transform2D &p_transform) {
set_transform(p_transform);
}
-void Node2D::set_z(int p_z) {
+void Node2D::set_z_index(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);
- _change_notify("z");
+ z_index = p_z;
+ VS::get_singleton()->canvas_item_set_z_index(get_canvas_item(), z_index);
+ _change_notify("z_index");
}
void Node2D::set_z_as_relative(bool p_enabled) {
@@ -351,9 +357,9 @@ bool Node2D::is_z_relative() const {
return z_relative;
}
-int Node2D::get_z() const {
+int Node2D::get_z_index() const {
- return z;
+ return z_index;
}
Transform2D Node2D::get_relative_transform_to_parent(const Node *p_parent) const {
@@ -427,8 +433,8 @@ void Node2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("to_local", "global_point"), &Node2D::to_local);
ClassDB::bind_method(D_METHOD("to_global", "local_point"), &Node2D::to_global);
- ClassDB::bind_method(D_METHOD("set_z", "z"), &Node2D::set_z);
- ClassDB::bind_method(D_METHOD("get_z"), &Node2D::get_z);
+ ClassDB::bind_method(D_METHOD("set_z_index", "z_index"), &Node2D::set_z_index);
+ ClassDB::bind_method(D_METHOD("get_z_index"), &Node2D::get_z_index);
ClassDB::bind_method(D_METHOD("set_z_as_relative", "enable"), &Node2D::set_z_as_relative);
ClassDB::bind_method(D_METHOD("is_z_relative"), &Node2D::is_z_relative);
@@ -442,14 +448,14 @@ void Node2D::_bind_methods() {
ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform", PROPERTY_HINT_NONE, "", 0), "set_transform", "get_transform");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_rotation", PROPERTY_HINT_NONE, "", 0), "set_global_rotation", "get_global_rotation");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_rotation_degrees", PROPERTY_HINT_NONE, "", 0), "set_global_rotation_degrees", "get_global_rotation_degrees");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "global_scale", PROPERTY_HINT_NONE, "", 0), "set_global_scale", "get_global_scale");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_transform", PROPERTY_HINT_NONE, "", 0), "set_global_transform", "get_global_transform");
- ADD_GROUP("Z", "");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "z", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z", "get_z");
+ ADD_GROUP("Z Index", "");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"), "set_z_index", "get_z_index");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "z_as_relative"), "set_z_as_relative", "is_z_relative");
}
@@ -458,6 +464,6 @@ Node2D::Node2D() {
angle = 0;
_scale = Vector2(1, 1);
_xform_dirty = false;
- z = 0;
+ z_index = 0;
z_relative = true;
}
diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h
index e1e07f2895..725686cdf8 100644
--- a/scene/2d/node_2d.h
+++ b/scene/2d/node_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NODE2D_H
#define NODE2D_H
@@ -39,7 +40,7 @@ class Node2D : public CanvasItem {
Point2 pos;
float angle;
Size2 _scale;
- int z;
+ int z_index;
bool z_relative;
Transform2D _mat;
@@ -61,12 +62,16 @@ public:
virtual void _edit_set_position(const Point2 &p_position);
virtual Point2 _edit_get_position() const;
- virtual void _edit_set_rect(const Rect2 &p_edit_rect);
- virtual bool _edit_use_rect() const;
+
+ virtual void _edit_set_scale(const Size2 &p_scale);
+ virtual Size2 _edit_get_scale() const;
+
virtual void _edit_set_rotation(float p_rotation);
virtual float _edit_get_rotation() const;
virtual bool _edit_use_rotation() const;
+ virtual void _edit_set_rect(const Rect2 &p_edit_rect);
+
void set_position(const Point2 &p_pos);
void set_rotation(float p_radians);
void set_rotation_degrees(float p_degrees);
@@ -96,8 +101,8 @@ public:
void set_global_rotation_degrees(float p_degrees);
void set_global_scale(const Size2 &p_scale);
- void set_z(int p_z);
- int get_z() const;
+ void set_z_index(int p_z);
+ int get_z_index() const;
void look_at(const Vector2 &p_pos);
float get_angle_to(const Vector2 &p_pos) const;
diff --git a/scene/2d/parallax_background.cpp b/scene/2d/parallax_background.cpp
index b9012e37b2..027d64b813 100644
--- a/scene/2d/parallax_background.cpp
+++ b/scene/2d/parallax_background.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "parallax_background.h"
#include "parallax_layer.h"
diff --git a/scene/2d/parallax_background.h b/scene/2d/parallax_background.h
index e37ec0db99..31d1c553a2 100644
--- a/scene/2d/parallax_background.h
+++ b/scene/2d/parallax_background.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PARALLAX_BACKGROUND_H
#define PARALLAX_BACKGROUND_H
diff --git a/scene/2d/parallax_layer.cpp b/scene/2d/parallax_layer.cpp
index 9da27caa4c..2ac6c76032 100644
--- a/scene/2d/parallax_layer.cpp
+++ b/scene/2d/parallax_layer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "parallax_layer.h"
#include "engine.h"
@@ -71,7 +72,7 @@ void ParallaxLayer::_update_mirroring() {
ParallaxBackground *pb = Object::cast_to<ParallaxBackground>(get_parent());
if (pb) {
- RID c = pb->get_world_2d()->get_canvas();
+ RID c = pb->get_canvas();
RID ci = get_canvas_item();
Point2 mirrorScale = mirroring * get_scale();
VisualServer::get_singleton()->canvas_set_item_mirroring(c, ci, mirrorScale);
@@ -119,7 +120,6 @@ void ParallaxLayer::set_base_offset_and_scale(const Point2 &p_offset, float p_sc
if (mirroring.x) {
double den = mirroring.x * p_scale;
- double before = new_ofs.x;
new_ofs.x -= den * ceil(new_ofs.x / den);
}
diff --git a/scene/2d/parallax_layer.h b/scene/2d/parallax_layer.h
index 6feb1fad67..b2b98b0ef6 100644
--- a/scene/2d/parallax_layer.h
+++ b/scene/2d/parallax_layer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PARALLAX_LAYER_H
#define PARALLAX_LAYER_H
diff --git a/scene/2d/particles_2d.cpp b/scene/2d/particles_2d.cpp
index 7d53557216..1da1d44b17 100644
--- a/scene/2d/particles_2d.cpp
+++ b/scene/2d/particles_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "particles_2d.h"
#include "engine.h"
@@ -35,8 +36,7 @@
void Particles2D::set_emitting(bool p_emitting) {
- emitting = p_emitting;
- VS::get_singleton()->particles_set_emitting(particles, emitting);
+ VS::get_singleton()->particles_set_emitting(particles, p_emitting);
}
void Particles2D::set_amount(int p_amount) {
@@ -56,7 +56,7 @@ void Particles2D::set_one_shot(bool p_enable) {
one_shot = p_enable;
VS::get_singleton()->particles_set_one_shot(particles, one_shot);
- if (!one_shot && emitting)
+ if (!one_shot && is_emitting())
VisualServer::get_singleton()->particles_restart(particles);
}
void Particles2D::set_pre_process_time(float p_time) {
@@ -134,7 +134,7 @@ void Particles2D::set_speed_scale(float p_scale) {
bool Particles2D::is_emitting() const {
- return emitting;
+ return VS::get_singleton()->particles_get_emitting(particles);
}
int Particles2D::get_amount() const {
@@ -367,9 +367,9 @@ void Particles2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("restart"), &Particles2D::restart);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01,or_greater"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
diff --git a/scene/2d/particles_2d.h b/scene/2d/particles_2d.h
index 6946f2a799..f367095581 100644
--- a/scene/2d/particles_2d.h
+++ b/scene/2d/particles_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PARTICLES_FRAME_H
#define PARTICLES_FRAME_H
@@ -47,7 +48,6 @@ public:
private:
RID particles;
- bool emitting;
bool one_shot;
int amount;
float lifetime;
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 4029ef137b..658b998d17 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,11 +27,61 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "path_2d.h"
#include "engine.h"
#include "scene/scene_string_names.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_scale.h"
+#endif
+
+Rect2 Path2D::_edit_get_rect() const {
+
+ if (!curve.is_valid() || curve->get_point_count() == 0)
+ return Rect2(0, 0, 0, 0);
+
+ Rect2 aabb = Rect2(curve->get_point_position(0), Vector2(0, 0));
+
+ for (int i = 0; i < curve->get_point_count(); i++) {
+
+ for (int j = 0; j <= 8; j++) {
+
+ real_t frac = j / 8.0;
+ Vector2 p = curve->interpolate(i, frac);
+ aabb.expand_to(p);
+ }
+ }
+
+ return aabb;
+}
+
+bool Path2D::_edit_use_rect() const {
+ return true;
+}
+
+bool Path2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ for (int i = 0; i < curve->get_point_count(); i++) {
+ Vector2 s[2];
+ s[0] = curve->get_point_position(i);
+
+ for (int j = 1; j <= 8; j++) {
+ real_t frac = j / 8.0;
+ s[1] = curve->interpolate(i, frac);
+
+ Vector2 p = Geometry::get_closest_point_to_segment_2d(p_point, s);
+ if (p.distance_to(p_point) <= p_tolerance)
+ return true;
+
+ s[0] = s[1];
+ }
+ }
+
+ return false;
+}
+
void Path2D::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW && curve.is_valid()) {
@@ -41,6 +91,13 @@ void Path2D::_notification(int p_what) {
return;
}
+#if TOOLS_ENABLED
+ const float line_width = 2 * EDSCALE;
+#else
+ const float line_width = 2;
+#endif
+ const Color color = Color(1.0, 1.0, 1.0, 1.0);
+
for (int i = 0; i < curve->get_point_count(); i++) {
Vector2 prev_p = curve->get_point_position(i);
@@ -49,7 +106,7 @@ void Path2D::_notification(int p_what) {
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);
+ draw_line(prev_p, p, color, line_width);
prev_p = p;
}
}
@@ -94,6 +151,7 @@ void Path2D::_bind_methods() {
Path2D::Path2D() {
set_curve(Ref<Curve2D>(memnew(Curve2D))); //create one by default
+ set_self_modulate(Color(0.5, 0.6, 1.0, 0.7));
}
/////////////////////////////////////////////////////////////////////////////////
@@ -191,66 +249,16 @@ bool PathFollow2D::get_cubic_interpolation() const {
return cubic;
}
-bool PathFollow2D::_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()->rotate) {
- set_rotate(p_value);
- } 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;
+void PathFollow2D::_validate_property(PropertyInfo &property) const {
- return true;
-}
+ if (property.name == "offset") {
-bool PathFollow2D::_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()->rotate) {
- r_ret = is_rotating();
- } 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;
+ float max = 10000;
+ if (path && path->get_curve().is_valid())
+ max = path->get_curve()->get_baked_length();
- return true;
-}
-void PathFollow2D::_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::BOOL, "rotate"));
- 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"));
+ property.hint_string = "0," + rtos(max) + ",0.01";
+ }
}
String PathFollow2D::get_configuration_warning() const {
@@ -287,6 +295,18 @@ void PathFollow2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow2D::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow2D::has_loop);
+
+ ClassDB::bind_method(D_METHOD("set_lookahead", "lookahead"), &PathFollow2D::set_lookahead);
+ ClassDB::bind_method(D_METHOD("get_lookahead"), &PathFollow2D::get_lookahead);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rotate"), "set_rotate", "is_rotating");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lookahead", PROPERTY_HINT_RANGE, "0.001,1024.0,0.001"), "set_lookahead", "get_lookahead");
}
void PathFollow2D::set_offset(float p_offset) {
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index 88a0abdea9..64696442c3 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PATH_2D_H
#define PATH_2D_H
@@ -46,6 +47,10 @@ protected:
static void _bind_methods();
public:
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_curve(const Ref<Curve2D> &p_curve);
Ref<Curve2D> get_curve() const;
@@ -70,9 +75,7 @@ private:
void _update_transform();
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;
+ virtual void _validate_property(PropertyInfo &property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/2d/path_texture.cpp b/scene/2d/path_texture.cpp
index 13644f71cf..d36a9fb65a 100644
--- a/scene/2d/path_texture.cpp
+++ b/scene/2d/path_texture.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "path_texture.h"
void PathTexture::set_begin_texture(const Ref<Texture> &p_texture) {
diff --git a/scene/2d/path_texture.h b/scene/2d/path_texture.h
index 4639a6072b..7a347c0653 100644
--- a/scene/2d/path_texture.h
+++ b/scene/2d/path_texture.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PATH_TEXTURE_H
#define PATH_TEXTURE_H
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index a1a1101b11..feb11089d0 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,8 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "physics_body_2d.h"
+#include "core/method_bind_ext.gen.inc"
#include "engine.h"
#include "scene/scene_string_names.h"
@@ -243,6 +245,7 @@ void RigidBody2D::_body_enter_tree(ObjectID p_id) {
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
+ ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(E->get().in_scene);
@@ -265,6 +268,7 @@ void RigidBody2D::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
+ ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(!E->get().in_scene);
@@ -290,6 +294,7 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
Object *obj = ObjectDB::get_instance(objid);
Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
/*if (obj) {
@@ -309,7 +314,7 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
E->get().in_scene = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
if (E->get().in_scene) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -338,7 +343,7 @@ void RigidBody2D::_body_inout(int p_status, ObjectID p_instance, int p_body_shap
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (in_scene)
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
}
@@ -358,19 +363,17 @@ struct _RigidBody2DInOut {
int local_shape;
};
-bool RigidBody2D::_test_motion(const Vector2 &p_motion, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) {
+bool RigidBody2D::_test_motion(const Vector2 &p_motion, bool p_infinite_inertia, float p_margin, const Ref<Physics2DTestMotionResult> &p_result) {
Physics2DServer::MotionResult *r = NULL;
if (p_result.is_valid())
r = p_result->get_result_ptr();
- return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_margin, r);
+ return Physics2DServer::get_singleton()->body_test_motion(get_rid(), get_global_transform(), p_motion, p_infinite_inertia, p_margin, r);
}
void RigidBody2D::_direct_state_changed(Object *p_state) {
-//eh.. fuck
#ifdef DEBUG_ENABLED
-
state = Object::cast_to<Physics2DDirectBodyState>(p_state);
#else
state = (Physics2DDirectBodyState *)p_state; //trust it
@@ -762,6 +765,14 @@ void RigidBody2D::set_contact_monitor(bool p_enabled) {
for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
//clean up mess
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = Object::cast_to<Node>(obj);
+
+ if (node) {
+
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ }
}
memdelete(contact_monitor);
@@ -806,7 +817,7 @@ String RigidBody2D::get_configuration_warning() const {
if (warning != String()) {
warning += "\n";
}
- warning += TTR("Size changes to RigidBody2D (in character or rigid modes) will be overriden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warning += TTR("Size changes to RigidBody2D (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
}
return warning;
@@ -876,7 +887,7 @@ void RigidBody2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_can_sleep", "able_to_sleep"), &RigidBody2D::set_can_sleep);
ClassDB::bind_method(D_METHOD("is_able_to_sleep"), &RigidBody2D::is_able_to_sleep);
- ClassDB::bind_method(D_METHOD("test_motion", "motion", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(0.08), DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("test_motion", "motion", "infinite_inertia", "margin", "result"), &RigidBody2D::_test_motion, DEFVAL(true), DEFVAL(0.08), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("_direct_state_changed"), &RigidBody2D::_direct_state_changed);
ClassDB::bind_method(D_METHOD("_body_enter_tree"), &RigidBody2D::_body_enter_tree);
@@ -888,6 +899,7 @@ void RigidBody2D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Rigid,Static,Character,Kinematic"), "set_mode", "get_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "inertia", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", 0), "set_inertia", "get_inertia");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01", PROPERTY_USAGE_EDITOR), "set_weight", "get_weight");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
@@ -904,6 +916,9 @@ void RigidBody2D::_bind_methods() {
ADD_GROUP("Angular", "angular_");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_damp", PROPERTY_HINT_RANGE, "-1,128,0.01"), "set_angular_damp", "get_angular_damp");
+ ADD_GROUP("Applied Forces", "applied_");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "applied_force"), "set_applied_force", "get_applied_force");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "applied_torque"), "set_applied_torque", "get_applied_torque");
ADD_SIGNAL(MethodInfo("body_shape_entered", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
ADD_SIGNAL(MethodInfo("body_shape_exited", PropertyInfo(Variant::INT, "body_id"), PropertyInfo(Variant::OBJECT, "body"), PropertyInfo(Variant::INT, "body_shape"), PropertyInfo(Variant::INT, "local_shape")));
@@ -956,11 +971,11 @@ RigidBody2D::~RigidBody2D() {
//////////////////////////
-Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion) {
+Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion, bool p_infinite_inertia) {
Collision col;
- if (move_and_collide(p_motion, col)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -974,11 +989,11 @@ Ref<KinematicCollision2D> KinematicBody2D::_move(const Vector2 &p_motion) {
return Ref<KinematicCollision2D>();
}
-bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, Collision &r_collision) {
+bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision) {
Transform2D gt = get_global_transform();
Physics2DServer::MotionResult result;
- bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, margin, &result);
+ bool colliding = Physics2DServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, margin, &result);
if (colliding) {
r_collision.collider_metadata = result.collider_metadata;
@@ -998,7 +1013,7 @@ bool KinematicBody2D::move_and_collide(const Vector2 &p_motion, Collision &r_col
return colliding;
}
-Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
+Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
Vector2 motion = (floor_velocity + p_linear_velocity) * get_physics_process_delta_time();
Vector2 lv = p_linear_velocity;
@@ -1013,7 +1028,7 @@ Vector2 KinematicBody2D::move_and_slide(const Vector2 &p_linear_velocity, const
Collision collision;
- bool collided = move_and_collide(motion, collision);
+ bool collided = move_and_collide(motion, p_infinite_inertia, collision);
if (collided) {
@@ -1080,11 +1095,11 @@ Vector2 KinematicBody2D::get_floor_velocity() const {
return floor_velocity;
}
-bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion) {
+bool KinematicBody2D::test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
- return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, margin);
+ return Physics2DServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia, margin);
}
void KinematicBody2D::set_safe_margin(float p_margin) {
@@ -1125,10 +1140,10 @@ Ref<KinematicCollision2D> KinematicBody2D::_get_slide_collision(int p_bounce) {
void KinematicBody2D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec"), &KinematicBody2D::_move);
- ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody2D::_move, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_bounces", "floor_max_angle"), &KinematicBody2D::move_and_slide, DEFVAL(Vector2(0, 0)), DEFVAL(true), DEFVAL(5), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody2D::test_move);
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody2D::test_move);
ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody2D::is_on_floor);
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody2D::is_on_ceiling);
diff --git a/scene/2d/physics_body_2d.h b/scene/2d/physics_body_2d.h
index b82771a8f4..0fda3c5c05 100644
--- a/scene/2d/physics_body_2d.h
+++ b/scene/2d/physics_body_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PHYSICS_BODY_2D_H
#define PHYSICS_BODY_2D_H
@@ -184,7 +185,7 @@ private:
void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape);
void _direct_state_changed(Object *p_state);
- bool _test_motion(const Vector2 &p_motion, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>());
+ bool _test_motion(const Vector2 &p_motion, bool p_infinite_inertia = true, float p_margin = 0.08, const Ref<Physics2DTestMotionResult> &p_result = Ref<Physics2DTestMotionResult>());
protected:
void _notification(int p_what);
@@ -295,20 +296,20 @@ private:
_FORCE_INLINE_ bool _ignores_mode(Physics2DServer::BodyMode) const;
- Ref<KinematicCollision2D> _move(const Vector2 &p_motion);
+ Ref<KinematicCollision2D> _move(const Vector2 &p_motion, bool p_infinite_inertia = true);
Ref<KinematicCollision2D> _get_slide_collision(int p_bounce);
protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector2 &p_motion, Collision &r_collision);
- bool test_move(const Transform2D &p_from, const Vector2 &p_motion);
+ bool move_and_collide(const Vector2 &p_motion, bool p_infinite_inertia, Collision &r_collision);
+ bool test_move(const Transform2D &p_from, const Vector2 &p_motion, bool p_infinite_inertia);
void set_safe_margin(float p_margin);
float get_safe_margin() const;
- Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), float p_slope_stop_min_velocity = 5, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
+ Vector2 move_and_slide(const Vector2 &p_linear_velocity, const Vector2 &p_floor_direction = Vector2(0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 5, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
diff --git a/scene/2d/polygon_2d.cpp b/scene/2d/polygon_2d.cpp
index 3f2ad19e51..4d6ebc81c3 100644
--- a/scene/2d/polygon_2d.cpp
+++ b/scene/2d/polygon_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,10 +27,35 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "polygon_2d.h"
+#include "core/math/geometry.h"
+#include "skeleton_2d.h"
+Dictionary Polygon2D::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["offset"] = offset;
+ return state;
+}
-Rect2 Polygon2D::_edit_get_rect() const {
+void Polygon2D::_edit_set_state(const Dictionary &p_state) {
+ Node2D::_edit_set_state(p_state);
+ set_offset(p_state["offset"]);
+}
+
+void Polygon2D::_edit_set_pivot(const Point2 &p_pivot) {
+ set_position(get_transform().xform(p_pivot));
+ set_offset(get_offset() - p_pivot);
+}
+
+Point2 Polygon2D::_edit_get_pivot() const {
+ return Vector2();
+}
+
+bool Polygon2D::_edit_use_pivot() const {
+ return true;
+}
+Rect2 Polygon2D::_edit_get_rect() const {
if (rect_cache_dirty) {
int l = polygon.size();
PoolVector<Vector2>::Read r = polygon.read();
@@ -42,25 +67,19 @@ Rect2 Polygon2D::_edit_get_rect() const {
else
item_rect.expand_to(pos);
}
- item_rect = item_rect.grow(20);
rect_cache_dirty = false;
}
return item_rect;
}
-void Polygon2D::_edit_set_pivot(const Point2 &p_pivot) {
-
- set_offset(p_pivot);
+bool Polygon2D::_edit_use_rect() const {
+ return true;
}
-Point2 Polygon2D::_edit_get_pivot() const {
-
- return get_offset();
-}
-bool Polygon2D::_edit_use_pivot() const {
+bool Polygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
- return true;
+ return Geometry::is_point_in_polygon(p_point - get_offset(), Variant(polygon));
}
void Polygon2D::_notification(int p_what) {
@@ -72,8 +91,20 @@ void Polygon2D::_notification(int p_what) {
if (polygon.size() < 3)
return;
+ Skeleton2D *skeleton_node = NULL;
+ if (has_node(skeleton)) {
+ skeleton_node = Object::cast_to<Skeleton2D>(get_node(skeleton));
+ }
+
+ if (skeleton_node)
+ VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), skeleton_node->get_skeleton());
+ else
+ VS::get_singleton()->canvas_item_attach_skeleton(get_canvas_item(), RID());
+
Vector<Vector2> points;
Vector<Vector2> uvs;
+ Vector<int> bones;
+ Vector<float> weights;
points.resize(polygon.size());
@@ -161,6 +192,70 @@ void Polygon2D::_notification(int p_what) {
}
}
+ if (!invert && bone_weights.size()) {
+ //a skeleton is set! fill indices and weights
+ int vc = points.size();
+ bones.resize(vc * 4);
+ weights.resize(vc * 4);
+
+ int *bonesw = bones.ptrw();
+ float *weightsw = weights.ptrw();
+
+ for (int i = 0; i < vc * 4; i++) {
+ bonesw[i] = 0;
+ weightsw[i] = 0;
+ }
+
+ for (int i = 0; i < bone_weights.size(); i++) {
+ if (bone_weights[i].weights.size() != points.size()) {
+ continue; //different number of vertices, sorry not using.
+ }
+ if (!skeleton_node->has_node(bone_weights[i].path)) {
+ continue; //node does not exist
+ }
+ Bone2D *bone = Object::cast_to<Bone2D>(skeleton_node->get_node(bone_weights[i].path));
+ if (!bone) {
+ continue;
+ }
+
+ int bone_index = bone->get_index_in_skeleton();
+ PoolVector<float>::Read r = bone_weights[i].weights.read();
+ for (int j = 0; j < vc; j++) {
+ if (r[j] == 0.0)
+ continue; //weight is unpainted, skip
+ //find an index with a weight
+ for (int k = 0; k < 4; k++) {
+ if (weightsw[j * 4 + k] < r[j]) {
+ //this is less than this weight, insert weight!
+ for (int l = 3; l > k; l--) {
+ weightsw[j * 4 + l] = weightsw[j * 4 + l - 1];
+ bonesw[j * 4 + l] = bonesw[j * 4 + l - 1];
+ }
+ weightsw[j * 4 + k] = r[j];
+ bonesw[j * 4 + k] = bone_index;
+ break;
+ }
+ }
+ }
+ }
+
+ //normalize the weights
+ for (int i = 0; i < vc; i++) {
+ float tw = 0;
+ for (int j = 0; j < 4; j++) {
+ tw += weightsw[i * 4 + j];
+ }
+ if (tw == 0)
+ continue; //unpainted, do nothing
+
+ //normalize
+ for (int j = 0; j < 4; j++) {
+ weightsw[i * 4 + j] /= tw;
+ // print_line("point " + itos(i) + " idx " + itos(j) + " index: " + itos(bonesw[i * 4 + j]) + " weight: " + rtos(weightsw[i * 4 + j]));
+ }
+ }
+ }
+
Vector<Color> colors;
int color_len = vertex_colors.size();
colors.resize(len);
@@ -177,7 +272,81 @@ void Polygon2D::_notification(int p_what) {
// Vector<int> indices = Geometry::triangulate_polygon(points);
// VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID());
- VS::get_singleton()->canvas_item_add_polygon(get_canvas_item(), points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID(), RID(), antialiased);
+ if (invert || splits.size() == 0) {
+ Vector<int> indices = Geometry::triangulate_polygon(points);
+ VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
+ } else {
+ //use splits
+ Vector<int> loop;
+ int sc = splits.size();
+ PoolVector<int>::Read r = splits.read();
+ int last = points.size();
+
+ Vector<Vector<int> > loops;
+
+ for (int i = 0; i < last; i++) {
+
+ int split;
+ int min_end = -1;
+
+ do {
+
+ loop.push_back(i);
+
+ split = -1;
+ int end = -1;
+
+ for (int j = 0; j < sc; j += 2) {
+ if (r[j + 1] >= last)
+ continue; //no longer valid
+ if (min_end != -1 && r[j + 1] >= min_end)
+ continue;
+ if (r[j] == i) {
+ if (split == -1 || r[j + 1] > end) {
+ split = r[j];
+ end = r[j + 1];
+ }
+ }
+ }
+
+ if (split != -1) {
+ for (int j = end; j < last; j++) {
+ loop.push_back(j);
+ }
+ loops.push_back(loop);
+ last = end + 1;
+ loop.clear();
+ min_end = end; //avoid this split from repeating
+ }
+
+ } while (split != -1);
+ }
+
+ if (loop.size()) {
+ loops.push_back(loop);
+ }
+
+ Vector<int> indices;
+
+ for (int i = 0; i < loops.size(); i++) {
+ Vector<int> loop = loops[i];
+ Vector<Vector2> vertices;
+ vertices.resize(loop.size());
+ for (int j = 0; j < vertices.size(); j++) {
+ vertices[j] = points[loop[j]];
+ }
+ Vector<int> sub_indices = Geometry::triangulate_polygon(vertices);
+ int from = indices.size();
+ indices.resize(from + sub_indices.size());
+ for (int j = 0; j < sub_indices.size(); j++) {
+ indices[from + j] = loop[sub_indices[j]];
+ }
+ }
+
+ //print_line("loops: " + itos(loops.size()) + " indices: " + itos(indices.size()));
+
+ VS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID());
+ }
} break;
}
@@ -205,6 +374,18 @@ PoolVector<Vector2> Polygon2D::get_uv() const {
return uv;
}
+void Polygon2D::set_splits(const PoolVector<int> &p_splits) {
+
+ ERR_FAIL_COND(p_splits.size() & 1); //splits should be multiple of 2
+ splits = p_splits;
+ update();
+}
+
+PoolVector<int> Polygon2D::get_splits() const {
+
+ return splits;
+}
+
void Polygon2D::set_color(const Color &p_color) {
color = p_color;
@@ -318,6 +499,7 @@ void Polygon2D::set_offset(const Vector2 &p_offset) {
offset = p_offset;
rect_cache_dirty = true;
update();
+ _change_notify("offset");
}
Vector2 Polygon2D::get_offset() const {
@@ -325,6 +507,74 @@ Vector2 Polygon2D::get_offset() const {
return offset;
}
+void Polygon2D::add_bone(const NodePath &p_path, const PoolVector<float> &p_weights) {
+
+ Bone bone;
+ bone.path = p_path;
+ bone.weights = p_weights;
+ bone_weights.push_back(bone);
+}
+int Polygon2D::get_bone_count() const {
+ return bone_weights.size();
+}
+NodePath Polygon2D::get_bone_path(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, bone_weights.size(), NodePath());
+ return bone_weights[p_index].path;
+}
+PoolVector<float> Polygon2D::get_bone_weights(int p_index) const {
+
+ ERR_FAIL_INDEX_V(p_index, bone_weights.size(), PoolVector<float>());
+ return bone_weights[p_index].weights;
+}
+void Polygon2D::erase_bone(int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx, bone_weights.size());
+ bone_weights.remove(p_idx);
+}
+
+void Polygon2D::clear_bones() {
+ bone_weights.clear();
+}
+
+void Polygon2D::set_bone_weights(int p_index, const PoolVector<float> &p_weights) {
+ ERR_FAIL_INDEX(p_index, bone_weights.size());
+ bone_weights[p_index].weights = p_weights;
+ update();
+}
+void Polygon2D::set_bone_path(int p_index, const NodePath &p_path) {
+ ERR_FAIL_INDEX(p_index, bone_weights.size());
+ bone_weights[p_index].path = p_path;
+ update();
+}
+
+Array Polygon2D::_get_bones() const {
+ Array bones;
+ for (int i = 0; i < get_bone_count(); i++) {
+ bones.push_back(get_bone_path(i));
+ bones.push_back(get_bone_weights(i));
+ }
+ return bones;
+}
+void Polygon2D::_set_bones(const Array &p_bones) {
+
+ ERR_FAIL_COND(p_bones.size() & 1);
+ clear_bones();
+ for (int i = 0; i < p_bones.size(); i += 2) {
+ add_bone(p_bones[i], p_bones[i + 1]);
+ }
+}
+
+void Polygon2D::set_skeleton(const NodePath &p_skeleton) {
+ if (skeleton == p_skeleton)
+ return;
+ skeleton = p_skeleton;
+ update();
+}
+
+NodePath Polygon2D::get_skeleton() const {
+ return skeleton;
+}
+
void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &Polygon2D::set_polygon);
@@ -336,6 +586,9 @@ void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color", "color"), &Polygon2D::set_color);
ClassDB::bind_method(D_METHOD("get_color"), &Polygon2D::get_color);
+ ClassDB::bind_method(D_METHOD("set_splits", "splits"), &Polygon2D::set_splits);
+ ClassDB::bind_method(D_METHOD("get_splits"), &Polygon2D::get_splits);
+
ClassDB::bind_method(D_METHOD("set_vertex_colors", "vertex_colors"), &Polygon2D::set_vertex_colors);
ClassDB::bind_method(D_METHOD("get_vertex_colors"), &Polygon2D::get_vertex_colors);
@@ -366,8 +619,24 @@ void Polygon2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &Polygon2D::set_offset);
ClassDB::bind_method(D_METHOD("get_offset"), &Polygon2D::get_offset);
+ ClassDB::bind_method(D_METHOD("add_bone", "path", "weights"), &Polygon2D::add_bone);
+ ClassDB::bind_method(D_METHOD("get_bone_count"), &Polygon2D::get_bone_count);
+ ClassDB::bind_method(D_METHOD("get_bone_path", "index"), &Polygon2D::get_bone_path);
+ ClassDB::bind_method(D_METHOD("get_bone_weights", "index"), &Polygon2D::get_bone_weights);
+ ClassDB::bind_method(D_METHOD("erase_bone", "index"), &Polygon2D::erase_bone);
+ ClassDB::bind_method(D_METHOD("clear_bones"), &Polygon2D::clear_bones);
+ ClassDB::bind_method(D_METHOD("set_bone_path", "index", "path"), &Polygon2D::set_bone_path);
+ ClassDB::bind_method(D_METHOD("set_bone_weights", "index", "weights"), &Polygon2D::set_bone_weights);
+
+ ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &Polygon2D::set_skeleton);
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &Polygon2D::get_skeleton);
+
+ ClassDB::bind_method(D_METHOD("_set_bones", "bones"), &Polygon2D::_set_bones);
+ ClassDB::bind_method(D_METHOD("_get_bones"), &Polygon2D::_get_bones);
+
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "uv"), "set_uv", "get_uv");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "splits"), "set_splits", "get_splits");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "vertex_colors"), "set_vertex_colors", "get_vertex_colors");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
@@ -377,11 +646,16 @@ void Polygon2D::_bind_methods() {
ADD_GROUP("Texture", "texture_");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_offset"), "set_texture_offset", "get_texture_offset");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "texture_scale"), "set_texture_scale", "get_texture_scale");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1"), "set_texture_rotation_degrees", "get_texture_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "texture_rotation", PROPERTY_HINT_NONE, "", 0), "set_texture_rotation", "get_texture_rotation");
+ ADD_GROUP("Skeleton", "");
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "skeleton"), "set_skeleton", "get_skeleton");
ADD_GROUP("Invert", "invert_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_enable"), "set_invert", "get_invert");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "invert_border", PROPERTY_HINT_RANGE, "0.1,16384,0.1"), "set_invert_border", "get_invert_border");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bones", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_bones", "_get_bones");
}
Polygon2D::Polygon2D() {
diff --git a/scene/2d/polygon_2d.h b/scene/2d/polygon_2d.h
index d09e22f5ff..575f71d74a 100644
--- a/scene/2d/polygon_2d.h
+++ b/scene/2d/polygon_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef POLYGON_2D_H
#define POLYGON_2D_H
@@ -39,6 +40,15 @@ class Polygon2D : public Node2D {
PoolVector<Vector2> polygon;
PoolVector<Vector2> uv;
PoolVector<Color> vertex_colors;
+ PoolVector<int> splits;
+
+ struct Bone {
+ NodePath path;
+ PoolVector<float> weights;
+ };
+
+ Vector<Bone> bone_weights;
+
Color color;
Ref<Texture> texture;
Size2 tex_scale;
@@ -53,17 +63,36 @@ class Polygon2D : public Node2D {
mutable bool rect_cache_dirty;
mutable Rect2 item_rect;
+ NodePath skeleton;
+
+ Array _get_bones() const;
+ void _set_bones(const Array &p_bones);
+
protected:
void _notification(int p_what);
static void _bind_methods();
public:
+ virtual Dictionary _edit_get_state() const;
+ virtual void _edit_set_state(const Dictionary &p_state);
+
+ virtual void _edit_set_pivot(const Point2 &p_pivot);
+ virtual Point2 _edit_get_pivot() const;
+ virtual bool _edit_use_pivot() const;
+ virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
+
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_polygon(const PoolVector<Vector2> &p_polygon);
PoolVector<Vector2> get_polygon() const;
void set_uv(const PoolVector<Vector2> &p_uv);
PoolVector<Vector2> get_uv() const;
+ void set_splits(const PoolVector<int> &p_uv);
+ PoolVector<int> get_splits() const;
+
void set_color(const Color &p_color);
Color get_color() const;
@@ -97,13 +126,17 @@ public:
void set_offset(const Vector2 &p_offset);
Vector2 get_offset() const;
- //editor stuff
-
- virtual void _edit_set_pivot(const Point2 &p_pivot);
- virtual Point2 _edit_get_pivot() const;
- virtual bool _edit_use_pivot() const;
-
- virtual Rect2 _edit_get_rect() const;
+ void add_bone(const NodePath &p_path = NodePath(), const PoolVector<float> &p_weights = PoolVector<float>());
+ int get_bone_count() const;
+ NodePath get_bone_path(int p_index) const;
+ PoolVector<float> get_bone_weights(int p_index) const;
+ void erase_bone(int p_idx);
+ void clear_bones();
+ void set_bone_weights(int p_index, const PoolVector<float> &p_weights);
+ void set_bone_path(int p_index, const NodePath &p_path);
+
+ void set_skeleton(const NodePath &p_skeleton);
+ NodePath get_skeleton() const;
Polygon2D();
};
diff --git a/scene/2d/position_2d.cpp b/scene/2d/position_2d.cpp
index 1e729bc179..64d23719e7 100644
--- a/scene/2d/position_2d.cpp
+++ b/scene/2d/position_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "position_2d.h"
#include "engine.h"
@@ -43,6 +44,10 @@ Rect2 Position2D::_edit_get_rect() const {
return Rect2(Point2(-10, -10), Size2(20, 20));
}
+bool Position2D::_edit_use_rect() const {
+ return false;
+}
+
void Position2D::_notification(int p_what) {
switch (p_what) {
diff --git a/scene/2d/position_2d.h b/scene/2d/position_2d.h
index 5961e447df..bff474cccd 100644
--- a/scene/2d/position_2d.h
+++ b/scene/2d/position_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef POSITION_2D_H
#define POSITION_2D_H
@@ -43,6 +44,7 @@ protected:
public:
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
Position2D();
};
diff --git a/scene/2d/ray_cast_2d.cpp b/scene/2d/ray_cast_2d.cpp
index a809023083..255d2d38d5 100644
--- a/scene/2d/ray_cast_2d.cpp
+++ b/scene/2d/ray_cast_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "ray_cast_2d.h"
#include "collision_object_2d.h"
@@ -100,7 +101,7 @@ void RayCast2D::set_enabled(bool p_enabled) {
enabled = p_enabled;
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint())
- set_physics_process(p_enabled);
+ set_physics_process_internal(p_enabled);
if (!p_enabled)
collided = false;
}
@@ -140,9 +141,9 @@ void RayCast2D::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled && !Engine::get_singleton()->is_editor_hint())
- set_physics_process(true);
+ set_physics_process_internal(true);
else
- set_physics_process(false);
+ set_physics_process_internal(false);
if (Object::cast_to<CollisionObject2D>(get_parent())) {
if (exclude_parent_body)
@@ -154,7 +155,7 @@ void RayCast2D::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
if (enabled)
- set_physics_process(false);
+ set_physics_process_internal(false);
} break;
@@ -182,7 +183,7 @@ void RayCast2D::_notification(int p_what) {
} break;
- case NOTIFICATION_PHYSICS_PROCESS: {
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (!enabled)
break;
diff --git a/scene/2d/ray_cast_2d.h b/scene/2d/ray_cast_2d.h
index 9d60a16c6a..0850cdc7cc 100644
--- a/scene/2d/ray_cast_2d.h
+++ b/scene/2d/ray_cast_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RAY_CAST_2D_H
#define RAY_CAST_2D_H
diff --git a/scene/2d/remote_transform_2d.cpp b/scene/2d/remote_transform_2d.cpp
index c139573853..da764e032b 100644
--- a/scene/2d/remote_transform_2d.cpp
+++ b/scene/2d/remote_transform_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "remote_transform_2d.h"
#include "scene/scene_string_names.h"
diff --git a/scene/2d/remote_transform_2d.h b/scene/2d/remote_transform_2d.h
index 30d5fd1e7c..3f395f820e 100644
--- a/scene/2d/remote_transform_2d.h
+++ b/scene/2d/remote_transform_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
+#ifndef REMOTE_TRANSFORM_2D_H
+#define REMOTE_TRANSFORM_2D_H
+
#include "scene/2d/node_2d.h"
class RemoteTransform2D : public Node2D {
@@ -69,3 +73,5 @@ public:
RemoteTransform2D();
};
+
+#endif // REMOTE_TRANSFORM_2D_H
diff --git a/scene/2d/screen_button.cpp b/scene/2d/screen_button.cpp
index d5fcda90d5..9480f18176 100644
--- a/scene/2d/screen_button.cpp
+++ b/scene/2d/screen_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "screen_button.h"
#include "input_map.h"
#include "os/input.h"
@@ -334,6 +335,10 @@ Rect2 TouchScreenButton::_edit_get_rect() const {
return Rect2(Size2(), texture->get_size());
}
+bool TouchScreenButton::_edit_use_rect() const {
+ return true;
+}
+
void TouchScreenButton::set_visibility_mode(VisibilityMode p_mode) {
visibility = p_mode;
update();
diff --git a/scene/2d/screen_button.h b/scene/2d/screen_button.h
index 2e674c20b4..b2fafcc93d 100644
--- a/scene/2d/screen_button.h
+++ b/scene/2d/screen_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCREEN_BUTTON_H
#define SCREEN_BUTTON_H
@@ -103,6 +104,7 @@ public:
bool is_pressed() const;
Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
TouchScreenButton();
};
diff --git a/scene/2d/skeleton_2d.cpp b/scene/2d/skeleton_2d.cpp
new file mode 100644
index 0000000000..0595cc43b8
--- /dev/null
+++ b/scene/2d/skeleton_2d.cpp
@@ -0,0 +1,308 @@
+/*************************************************************************/
+/* skeleton_2d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "skeleton_2d.h"
+
+void Bone2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ Node *parent = get_parent();
+ parent_bone = Object::cast_to<Bone2D>(parent);
+ skeleton = NULL;
+ while (parent) {
+ skeleton = Object::cast_to<Skeleton2D>(parent);
+ if (skeleton)
+ break;
+ if (!Object::cast_to<Bone2D>(parent))
+ break; //skeletons must be chained to Bone2Ds.
+
+ parent = parent->get_parent();
+ }
+
+ if (skeleton) {
+ Skeleton2D::Bone bone;
+ bone.bone = this;
+ skeleton->bones.push_back(bone);
+ skeleton->_make_bone_setup_dirty();
+ }
+ }
+ if (p_what == NOTIFICATION_LOCAL_TRANSFORM_CHANGED) {
+ if (skeleton) {
+ skeleton->_make_transform_dirty();
+ }
+ }
+ if (p_what == NOTIFICATION_MOVED_IN_PARENT) {
+ if (skeleton) {
+ skeleton->_make_bone_setup_dirty();
+ }
+ }
+
+ if (p_what == NOTIFICATION_EXIT_TREE) {
+ if (skeleton) {
+ for (int i = 0; i < skeleton->bones.size(); i++) {
+ if (skeleton->bones[i].bone == this) {
+ skeleton->bones.remove(i);
+ break;
+ }
+ }
+ skeleton->_make_bone_setup_dirty();
+ skeleton = NULL;
+ }
+ parent_bone = NULL;
+ }
+}
+void Bone2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_rest", "rest"), &Bone2D::set_rest);
+ ClassDB::bind_method(D_METHOD("get_rest"), &Bone2D::get_rest);
+ ClassDB::bind_method(D_METHOD("apply_rest"), &Bone2D::apply_rest);
+ ClassDB::bind_method(D_METHOD("get_skeleton_rest"), &Bone2D::get_skeleton_rest);
+ ClassDB::bind_method(D_METHOD("get_index_in_skeleton"), &Bone2D::get_index_in_skeleton);
+
+ ClassDB::bind_method(D_METHOD("set_default_length", "default_length"), &Bone2D::set_default_length);
+ ClassDB::bind_method(D_METHOD("get_default_length"), &Bone2D::get_default_length);
+
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D,"rest"),"set_rest","get_rest");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL,"default_length",PROPERTY_HINT_RANGE,"1,1024,1"),"set_default_length","get_default_length");
+}
+
+void Bone2D::set_rest(const Transform2D &p_rest) {
+ rest = p_rest;
+ if (skeleton)
+ skeleton->_make_bone_setup_dirty();
+
+ update_configuration_warning();
+}
+
+Transform2D Bone2D::get_rest() const {
+ return rest;
+}
+
+Transform2D Bone2D::get_skeleton_rest() const {
+
+ if (parent_bone) {
+ return parent_bone->get_skeleton_rest() * rest;
+ } else {
+ return rest;
+ }
+}
+
+void Bone2D::apply_rest() {
+ set_transform(rest);
+}
+
+void Bone2D::set_default_length(float p_length) {
+
+ default_length=p_length;
+
+}
+
+float Bone2D::get_default_length() const {
+ return default_length;
+}
+
+int Bone2D::get_index_in_skeleton() const {
+ ERR_FAIL_COND_V(!skeleton,-1);
+ skeleton->_update_bone_setup();
+ return skeleton_index;
+}
+String Bone2D::get_configuration_warning() const {
+
+ String warning = Node2D::get_configuration_warning();
+ if (!skeleton) {
+ if (warning!=String()) {
+ warning+="\n";
+ }
+ if (parent_bone) {
+ warning+=TTR("This Bone2D chain should end at a Skeleton2D node.");
+ } else {
+ warning+=TTR("A Bone2D only works with a Skeleton2D or another Bone2D as parent node.");
+ }
+ }
+
+ if (rest==Transform2D(0,0,0,0,0,0)) {
+ if (warning!=String()) {
+ warning+="\n";
+ }
+ warning+=TTR("This bone lacks a proper REST pose. Go to the Skeleton2D node and set one.");
+
+ }
+
+ return warning;
+}
+
+Bone2D::Bone2D() {
+ skeleton = NULL;
+ parent_bone = NULL;
+ skeleton_index=-1;
+ default_length=16;
+ set_notify_local_transform(true);
+ //this is a clever hack so the bone knows no rest has been set yet, allowing to show an error.
+ for(int i=0;i<3;i++) {
+ rest[i]=Vector2(0,0);
+ }
+}
+
+//////////////////////////////////////
+
+void Skeleton2D::_make_bone_setup_dirty() {
+
+ if (bone_setup_dirty)
+ return;
+ bone_setup_dirty = true;
+ if (is_inside_tree()) {
+ call_deferred("_update_bone_setup");
+ }
+}
+
+void Skeleton2D::_update_bone_setup() {
+
+ if (!bone_setup_dirty)
+ return;
+
+ bone_setup_dirty = false;
+ VS::get_singleton()->skeleton_allocate(skeleton, bones.size(), true);
+
+ bones.sort(); //sorty so they are always in the same order/index
+
+ for (int i = 0; i < bones.size(); i++) {
+ bones[i].rest_inverse = bones[i].bone->get_skeleton_rest().affine_inverse(); //bind pose
+ bones[i].bone->skeleton_index=i;
+ Bone2D *parent_bone = Object::cast_to<Bone2D>(bones[i].bone->get_parent());
+ if (parent_bone) {
+ bones[i].parent_index=parent_bone->skeleton_index;
+ } else {
+ bones[i].parent_index=-1;
+ }
+ }
+
+ transform_dirty = true;
+ _update_transform();
+}
+
+void Skeleton2D::_make_transform_dirty() {
+
+ if (transform_dirty)
+ return;
+ transform_dirty = true;
+ if (is_inside_tree()) {
+ call_deferred("_update_transform");
+ }
+}
+
+void Skeleton2D::_update_transform() {
+
+ if (bone_setup_dirty) {
+ _update_bone_setup();
+ return; //above will update transform anyway
+ }
+ if (!transform_dirty)
+ return;
+
+ transform_dirty = false;
+
+ for (int i = 0; i < bones.size(); i++) {
+
+ ERR_CONTINUE(bones[i].parent_index>=i);
+ if (bones[i].parent_index>=0) {
+ bones[i].accum_transform = bones[bones[i].parent_index].accum_transform * bones[i].bone->get_transform();
+ } else {
+ bones[i].accum_transform = bones[i].bone->get_transform();
+ }
+ }
+
+ for (int i = 0; i < bones.size(); i++) {
+
+ Transform2D final_xform = bones[i].accum_transform * bones[i].rest_inverse;
+ VS::get_singleton()->skeleton_bone_set_transform_2d(skeleton, i, final_xform);
+ }
+}
+
+int Skeleton2D::get_bone_count() const {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), 0);
+
+ if (bone_setup_dirty) {
+ const_cast<Skeleton2D *>(this)->_update_bone_setup();
+ }
+
+ return bones.size();
+}
+
+Bone2D *Skeleton2D::get_bone(int p_idx) {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), NULL);
+ ERR_FAIL_INDEX_V(p_idx, bones.size(), NULL);
+
+ return bones[p_idx].bone;
+}
+
+void Skeleton2D::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_READY) {
+
+ if (bone_setup_dirty)
+ _update_bone_setup();
+ if (transform_dirty)
+ _update_transform();
+
+ request_ready();
+ }
+
+ if (p_what == NOTIFICATION_TRANSFORM_CHANGED) {
+ VS::get_singleton()->skeleton_set_base_transform_2d(skeleton,get_global_transform());
+ }
+}
+
+RID Skeleton2D::get_skeleton() const {
+ return skeleton;
+}
+void Skeleton2D::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_update_bone_setup"), &Skeleton2D::_update_bone_setup);
+ ClassDB::bind_method(D_METHOD("_update_transform"), &Skeleton2D::_update_transform);
+
+ ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton2D::get_bone_count);
+ ClassDB::bind_method(D_METHOD("get_bone"), &Skeleton2D::get_bone);
+
+ ClassDB::bind_method(D_METHOD("get_skeleton"), &Skeleton2D::get_skeleton);
+}
+
+Skeleton2D::Skeleton2D() {
+ bone_setup_dirty = true;
+ transform_dirty = true;
+
+ skeleton = VS::get_singleton()->skeleton_create();
+}
+
+Skeleton2D::~Skeleton2D() {
+
+ VS::get_singleton()->free(skeleton);
+}
diff --git a/scene/2d/skeleton_2d.h b/scene/2d/skeleton_2d.h
new file mode 100644
index 0000000000..b86cf3be81
--- /dev/null
+++ b/scene/2d/skeleton_2d.h
@@ -0,0 +1,109 @@
+/*************************************************************************/
+/* skeleton_2d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 SKELETON_2D_H
+#define SKELETON_2D_H
+
+#include "scene/2d/node_2d.h"
+
+class Skeleton2D;
+
+class Bone2D : public Node2D {
+ GDCLASS(Bone2D, Node2D)
+
+ Bone2D *parent_bone;
+ Skeleton2D *skeleton;
+ Transform2D rest;
+ float default_length;
+
+friend class Skeleton2D;
+ int skeleton_index;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void set_rest(const Transform2D &p_rest);
+ Transform2D get_rest() const;
+ void apply_rest();
+ Transform2D get_skeleton_rest() const;
+
+ String get_configuration_warning() const;
+
+ void set_default_length(float p_length);
+ float get_default_length() const;
+
+ int get_index_in_skeleton() const;
+
+ Bone2D();
+};
+
+class Skeleton2D : public Node2D {
+ GDCLASS(Skeleton2D, Node2D);
+
+ friend class Bone2D;
+
+ struct Bone {
+ bool operator<(const Bone &p_bone) const {
+ return p_bone.bone->is_greater_than(bone);
+ }
+ Bone2D *bone;
+ int parent_index;
+ Transform2D accum_transform;
+ Transform2D rest_inverse;
+ };
+
+ Vector<Bone> bones;
+
+ bool bone_setup_dirty;
+ void _make_bone_setup_dirty();
+ void _update_bone_setup();
+
+ bool transform_dirty;
+ void _make_transform_dirty();
+ void _update_transform();
+
+ RID skeleton;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ int get_bone_count() const;
+ Bone2D *get_bone(int p_idx);
+
+ RID get_skeleton() const;
+ Skeleton2D();
+ ~Skeleton2D();
+};
+
+#endif // SKELETON_2D_H
diff --git a/scene/2d/sprite.cpp b/scene/2d/sprite.cpp
index df2265aae9..64d0771fab 100644
--- a/scene/2d/sprite.cpp
+++ b/scene/2d/sprite.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,26 +27,79 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "sprite.h"
#include "core/core_string_names.h"
#include "os/os.h"
#include "scene/main/viewport.h"
#include "scene/scene_string_names.h"
-void Sprite::_edit_set_pivot(const Point2 &p_pivot) {
+Dictionary Sprite::_edit_get_state() const {
+ Dictionary state = Node2D::_edit_get_state();
+ state["offset"] = offset;
+ return state;
+}
- set_offset(p_pivot);
+void Sprite::_edit_set_state(const Dictionary &p_state) {
+ Node2D::_edit_set_state(p_state);
+ set_offset(p_state["offset"]);
}
-Point2 Sprite::_edit_get_pivot() const {
+void Sprite::_edit_set_pivot(const Point2 &p_pivot) {
+ set_offset(get_offset() - p_pivot);
+ set_position(get_transform().xform(p_pivot));
+}
- return get_offset();
+Point2 Sprite::_edit_get_pivot() const {
+ return Vector2();
}
+
bool Sprite::_edit_use_pivot() const {
+ return true;
+}
+
+Rect2 Sprite::_edit_get_rect() const {
+ return get_rect();
+}
+bool Sprite::_edit_use_rect() const {
return true;
}
+void Sprite::_get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const {
+
+ Rect2 base_rect;
+
+ if (region) {
+ r_filter_clip = region_filter_clip;
+ base_rect = region_rect;
+ } else {
+ r_filter_clip = false;
+ base_rect = Rect2(0, 0, texture->get_width(), texture->get_height());
+ }
+
+ Size2 frame_size = base_rect.size / Size2(hframes, vframes);
+ Point2 frame_offset = Point2(frame % hframes, frame / hframes);
+ frame_offset *= frame_size;
+
+ r_src_rect.size = frame_size;
+ r_src_rect.position = base_rect.position + frame_offset;
+
+ Point2 dest_offset = offset;
+ if (centered)
+ dest_offset -= frame_size / 2;
+ if (Engine::get_singleton()->get_use_pixel_snap()) {
+ dest_offset = dest_offset.floor();
+ }
+
+ r_dst_rect = Rect2(dest_offset, frame_size);
+
+ if (hflip)
+ r_dst_rect.size.x = -r_dst_rect.size.x;
+ if (vflip)
+ r_dst_rect.size.y = -r_dst_rect.size.y;
+}
+
void Sprite::_notification(int p_what) {
switch (p_what) {
@@ -63,38 +116,9 @@ void Sprite::_notification(int p_what) {
break;
*/
- Size2 s;
- Rect2 src_rect;
- bool filter_clip = false;
-
- if (region) {
-
- s = region_rect.size;
- src_rect = region_rect;
- filter_clip = region_filter_clip;
- } else {
- s = Size2(texture->get_size());
- s = s / Size2(hframes, vframes);
-
- src_rect.size = s;
- src_rect.position.x += float(frame % hframes) * s.x;
- src_rect.position.y += float(frame / hframes) * s.y;
- }
-
- Point2 ofs = offset;
- if (centered)
- ofs -= s / 2;
- if (Engine::get_singleton()->get_use_pixel_snap()) {
- ofs = ofs.floor();
- }
-
- Rect2 dst_rect(ofs, s);
-
- if (hflip)
- dst_rect.size.x = -dst_rect.size.x;
- if (vflip)
- dst_rect.size.y = -dst_rect.size.y;
-
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
texture->draw_rect_region(ci, dst_rect, src_rect, Color(1, 1, 1), false, normal_map, filter_clip);
} break;
@@ -105,7 +129,15 @@ void Sprite::set_texture(const Ref<Texture> &p_texture) {
if (p_texture == texture)
return;
+
+ if (texture.is_valid())
+ texture->remove_change_receptor(this);
+
texture = p_texture;
+
+ if (texture.is_valid())
+ texture->add_change_receptor(this);
+
update();
emit_signal("texture_changed");
item_rect_changed();
@@ -257,7 +289,81 @@ int Sprite::get_hframes() const {
return hframes;
}
-Rect2 Sprite::_edit_get_rect() const {
+bool Sprite::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ if (texture.is_null())
+ return false;
+
+ Rect2 src_rect, dst_rect;
+ bool filter_clip;
+ _get_rects(src_rect, dst_rect, filter_clip);
+ dst_rect.size = dst_rect.size.abs();
+
+ if (!dst_rect.has_point(p_point))
+ return false;
+
+ Vector2 q = (p_point - dst_rect.position) / dst_rect.size;
+ if (hflip)
+ q.x = 1.0f - q.x;
+ if (vflip)
+ q.y = 1.0f - q.y;
+ q = q * src_rect.size + src_rect.position;
+
+ Ref<Image> image;
+ Ref<AtlasTexture> atlasTexture = texture;
+ if (atlasTexture.is_null()) {
+ image = texture->get_data();
+ } else {
+ ERR_FAIL_COND_V(atlasTexture->get_atlas().is_null(), false);
+
+ image = atlasTexture->get_atlas()->get_data();
+
+ Rect2 region = atlasTexture->get_region();
+ Rect2 margin = atlasTexture->get_margin();
+
+ q -= margin.position;
+
+ if ((q.x > region.size.width) || (q.y > region.size.height)) {
+ return false;
+ }
+
+ q += region.position;
+ }
+
+ ERR_FAIL_COND_V(image.is_null(), false);
+ if (image->is_compressed()) {
+ return dst_rect.has_point(p_point);
+ }
+
+ bool is_repeat = texture->get_flags() & Texture::FLAG_REPEAT;
+ bool is_mirrored_repeat = texture->get_flags() & Texture::FLAG_MIRRORED_REPEAT;
+ if (is_repeat) {
+ int mirror_x = 0;
+ int mirror_y = 0;
+ if (is_mirrored_repeat) {
+ mirror_x = (int)(q.x / texture->get_size().width);
+ mirror_y = (int)(q.y / texture->get_size().height);
+ }
+ q.x = Math::fmod(q.x, texture->get_size().width);
+ q.y = Math::fmod(q.y, texture->get_size().height);
+ if (mirror_x % 2 == 1) {
+ q.x = texture->get_size().width - q.x - 1;
+ }
+ if (mirror_y % 2 == 1) {
+ q.y = texture->get_size().height - q.y - 1;
+ }
+ } else {
+ q.x = MIN(q.x, texture->get_size().width - 1);
+ q.y = MIN(q.y, texture->get_size().height - 1);
+ }
+ image->lock();
+ const Color c = image->get_pixel((int)q.x, (int)q.y);
+ image->unlock();
+
+ return c.a > 0.01;
+}
+
+Rect2 Sprite::get_rect() const {
if (texture.is_null())
return Rect2(0, 0, 1, 1);
@@ -269,13 +375,13 @@ Rect2 Sprite::_edit_get_rect() const {
Size2i s;
if (region) {
-
s = region_rect.size;
} else {
s = texture->get_size();
- s = s / Point2(hframes, vframes);
}
+ s = s / Point2(hframes, vframes);
+
Point2 ofs = offset;
if (centered)
ofs -= s / 2;
@@ -296,6 +402,15 @@ void Sprite::_validate_property(PropertyInfo &property) const {
}
}
+void Sprite::_changed_callback(Object *p_changed, const char *p_prop) {
+
+ // Changes to the texture need to trigger an update to make
+ // the editor redraw the sprite with the updated texture.
+ if (texture.is_valid() && texture.ptr() == p_changed) {
+ update();
+ }
+}
+
void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture", "texture"), &Sprite::set_texture);
@@ -334,6 +449,8 @@ void Sprite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hframes", "hframes"), &Sprite::set_hframes);
ClassDB::bind_method(D_METHOD("get_hframes"), &Sprite::get_hframes);
+ ClassDB::bind_method(D_METHOD("get_rect"), &Sprite::get_rect);
+
ADD_SIGNAL(MethodInfo("frame_changed"));
ADD_SIGNAL(MethodInfo("texture_changed"));
@@ -368,3 +485,8 @@ Sprite::Sprite() {
vframes = 1;
hframes = 1;
}
+
+Sprite::~Sprite() {
+ if (texture.is_valid())
+ texture->remove_change_receptor(this);
+}
diff --git a/scene/2d/sprite.h b/scene/2d/sprite.h
index 1bef73c0a5..609ad8bb34 100644
--- a/scene/2d/sprite.h
+++ b/scene/2d/sprite.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPRITE_H
#define SPRITE_H
@@ -54,6 +55,8 @@ class Sprite : public Node2D {
int vframes;
int hframes;
+ void _get_rects(Rect2 &r_src_rect, Rect2 &r_dst_rect, bool &r_filter_clip) const;
+
protected:
void _notification(int p_what);
@@ -61,11 +64,19 @@ protected:
virtual void _validate_property(PropertyInfo &property) const;
+ virtual void _changed_callback(Object *p_changed, const char *p_prop);
+
public:
+ virtual Dictionary _edit_get_state() const;
+ virtual void _edit_set_state(const Dictionary &p_state);
+
virtual void _edit_set_pivot(const Point2 &p_pivot);
virtual Point2 _edit_get_pivot() const;
virtual bool _edit_use_pivot() const;
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
void set_texture(const Ref<Texture> &p_texture);
Ref<Texture> get_texture() const;
@@ -103,7 +114,10 @@ public:
void set_hframes(int p_amount);
int get_hframes() const;
+ Rect2 get_rect() const;
+
Sprite();
+ ~Sprite();
};
#endif // SPRITE_H
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 1e34372d1e..d88e148b2c 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tile_map.h"
#include "io/marshalls.h"
@@ -60,6 +61,7 @@ void TileMap::_notification(int p_what) {
}
pending_update = true;
+ _recreate_quadrants();
_update_dirty_quadrants();
RID space = get_world_2d()->get_space();
_update_quadrant_transform();
@@ -141,16 +143,20 @@ void TileMap::_update_quadrant_transform() {
void TileMap::set_tileset(const Ref<TileSet> &p_tileset) {
- if (tile_set.is_valid())
+ if (tile_set.is_valid()) {
tile_set->disconnect("changed", this, "_recreate_quadrants");
+ tile_set->remove_change_receptor(this);
+ }
_clear_quadrants();
tile_set = p_tileset;
- if (tile_set.is_valid())
+ if (tile_set.is_valid()) {
tile_set->connect("changed", this, "_recreate_quadrants");
- else
+ tile_set->add_change_receptor(this);
+ } else {
clear();
+ }
_recreate_quadrants();
emit_signal("settings_changed");
@@ -260,12 +266,18 @@ void TileMap::_update_dirty_quadrants() {
SceneTree *st = SceneTree::get_singleton();
Color debug_collision_color;
+ Color debug_navigation_color;
bool debug_shapes = st && st->is_debugging_collisions_hint();
if (debug_shapes) {
debug_collision_color = st->get_debug_collisions_color();
}
+ bool debug_navigation = st && st->is_debugging_navigation_hint();
+ if (debug_navigation) {
+ debug_navigation_color = st->get_debug_navigation_color();
+ }
+
while (dirty_quadrant_list.first()) {
Quadrant &q = *dirty_quadrant_list.first()->self();
@@ -293,6 +305,7 @@ void TileMap::_update_dirty_quadrants() {
}
q.occluder_instances.clear();
Ref<ShaderMaterial> prev_material;
+ int prev_z_index;
RID prev_canvas_item;
RID prev_debug_canvas_item;
@@ -313,11 +326,12 @@ void TileMap::_update_dirty_quadrants() {
continue;
Ref<ShaderMaterial> mat = tile_set->tile_get_material(c.id);
+ int z_index = tile_set->tile_get_z_index(c.id);
RID canvas_item;
RID debug_canvas_item;
- if (prev_canvas_item == RID() || prev_material != mat) {
+ if (prev_canvas_item == RID() || prev_material != mat || prev_z_index != z_index) {
canvas_item = vs->canvas_item_create();
if (mat.is_valid())
@@ -328,6 +342,7 @@ void TileMap::_update_dirty_quadrants() {
xform.set_origin(q.pos);
vs->canvas_item_set_transform(canvas_item, xform);
vs->canvas_item_set_light_mask(canvas_item, get_light_mask());
+ vs->canvas_item_set_z_index(canvas_item, z_index);
q.canvas_items.push_back(canvas_item);
@@ -336,13 +351,14 @@ void TileMap::_update_dirty_quadrants() {
debug_canvas_item = vs->canvas_item_create();
vs->canvas_item_set_parent(debug_canvas_item, canvas_item);
vs->canvas_item_set_z_as_relative_to_parent(debug_canvas_item, false);
- vs->canvas_item_set_z(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1);
+ vs->canvas_item_set_z_index(debug_canvas_item, VS::CANVAS_ITEM_Z_MAX - 1);
q.canvas_items.push_back(debug_canvas_item);
prev_debug_canvas_item = debug_canvas_item;
}
prev_canvas_item = canvas_item;
prev_material = mat;
+ prev_z_index = z_index;
} else {
canvas_item = prev_canvas_item;
@@ -352,7 +368,7 @@ void TileMap::_update_dirty_quadrants() {
}
Rect2 r = tile_set->tile_get_region(c.id);
- if (tile_set->tile_get_is_autotile(c.id)) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
int spacing = tile_set->autotile_get_spacing(c.id);
r.size = tile_set->autotile_get_size(c.id);
r.position += (r.size + Vector2(spacing, spacing)) * Vector2(c.autotile_coord_x, c.autotile_coord_y);
@@ -446,7 +462,7 @@ void TileMap::_update_dirty_quadrants() {
for (int i = 0; i < shapes.size(); i++) {
Ref<Shape2D> shape = shapes[i].shape;
if (shape.is_valid()) {
- if (!tile_set->tile_get_is_autotile(c.id) || (shapes[i].autotile_coord.x == c.autotile_coord_x && shapes[i].autotile_coord.y == c.autotile_coord_y)) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::SINGLE_TILE || (shapes[i].autotile_coord.x == c.autotile_coord_x && shapes[i].autotile_coord.y == c.autotile_coord_y)) {
Transform2D xform;
xform.set_origin(offset.floor());
@@ -473,7 +489,7 @@ void TileMap::_update_dirty_quadrants() {
if (navigation) {
Ref<NavigationPolygon> navpoly;
Vector2 npoly_ofs;
- if (tile_set->tile_get_is_autotile(c.id)) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
navpoly = tile_set->autotile_get_navigation_polygon(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
npoly_ofs = Vector2();
} else {
@@ -486,17 +502,66 @@ void TileMap::_update_dirty_quadrants() {
xform.set_origin(offset.floor() + q.pos);
_fix_cell_transform(xform, c, npoly_ofs + center_ofs, s);
- int pid = navigation->navpoly_create(navpoly, nav_rel * xform);
+ int pid = navigation->navpoly_add(navpoly, nav_rel * xform);
Quadrant::NavPoly np;
np.id = pid;
np.xform = xform;
q.navpoly_ids[E->key()] = np;
+
+ if (debug_navigation) {
+ RID debug_navigation_item = vs->canvas_item_create();
+ vs->canvas_item_set_parent(debug_navigation_item, canvas_item);
+ vs->canvas_item_set_z_as_relative_to_parent(debug_navigation_item, false);
+ vs->canvas_item_set_z_index(debug_navigation_item, VS::CANVAS_ITEM_Z_MAX - 2); // Display one below collision debug
+
+ if (debug_navigation_item.is_valid()) {
+ PoolVector<Vector2> navigation_polygon_vertices = navpoly->get_vertices();
+ int vsize = navigation_polygon_vertices.size();
+
+ if (vsize > 2) {
+ Vector<Color> colors;
+ Vector<Vector2> vertices;
+ vertices.resize(vsize);
+ colors.resize(vsize);
+ {
+ PoolVector<Vector2>::Read vr = navigation_polygon_vertices.read();
+ for (int i = 0; i < vsize; i++) {
+ vertices[i] = vr[i];
+ colors[i] = debug_navigation_color;
+ }
+ }
+
+ Vector<int> indices;
+
+ for (int i = 0; i < navpoly->get_polygon_count(); i++) {
+ Vector<int> polygon = navpoly->get_polygon(i);
+
+ for (int j = 2; j < polygon.size(); j++) {
+
+ int kofs[3] = { 0, j - 1, j };
+ for (int k = 0; k < 3; k++) {
+
+ int idx = polygon[kofs[k]];
+ ERR_FAIL_INDEX(idx, vsize);
+ indices.push_back(idx);
+ }
+ }
+ }
+ Transform2D navxform;
+ navxform.set_origin(offset.floor());
+ _fix_cell_transform(navxform, c, npoly_ofs + center_ofs, s);
+
+ vs->canvas_item_set_transform(debug_navigation_item, navxform);
+ vs->canvas_item_add_triangle_array(debug_navigation_item, indices, vertices, colors);
+ }
+ }
+ }
}
}
Ref<OccluderPolygon2D> occluder;
- if (tile_set->tile_get_is_autotile(c.id)) {
+ if (tile_set->tile_get_tile_mode(c.id) == TileSet::AUTO_TILE) {
occluder = tile_set->autotile_get_light_occluder(c.id, Vector2(c.autotile_coord_x, c.autotile_coord_y));
} else {
occluder = tile_set->tile_get_light_occluder(c.id);
@@ -652,7 +717,7 @@ void TileMap::_make_quadrant_dirty(Map<PosKey, Quadrant>::Element *Q) {
pending_update = true;
if (!is_inside_tree())
return;
- call_deferred("_update_dirty_quadrants");
+ _update_dirty_quadrants();
}
void TileMap::set_cellv(const Vector2 &p_pos, int p_tile, bool p_flip_x, bool p_flip_y, bool p_transpose) {
@@ -739,13 +804,33 @@ void TileMap::update_bitmask_area(const Vector2 &p_pos) {
}
}
+void TileMap::update_bitmask_region(const Vector2 &p_start, const Vector2 &p_end) {
+
+ if ((p_end.x < p_start.x || p_end.y < p_start.y) || (p_end.x == p_start.x && p_end.y == p_start.y)) {
+ int i;
+ Array a = get_used_cells();
+ for (i = 0; i < a.size(); i++) {
+ // update_bitmask_area() in order to update cells adjacent to the
+ // current cell, since ordering in array may not be reliable
+ Vector2 vector = (Vector2)a[i];
+ update_bitmask_area(Vector2(vector.x, vector.y));
+ }
+ return;
+ }
+ for (int x = p_start.x - 1; x <= p_end.x + 1; x++) {
+ for (int y = p_start.y - 1; y <= p_end.y + 1; y++) {
+ update_cell_bitmask(x, y);
+ }
+ }
+}
+
void TileMap::update_cell_bitmask(int p_x, int p_y) {
PosKey p(p_x, p_y);
Map<PosKey, Cell>::Element *E = tile_map.find(p);
if (E != NULL) {
int id = get_cell(p_x, p_y);
- if (tile_set->tile_get_is_autotile(id)) {
+ if (tile_set->tile_get_tile_mode(id) == TileSet::AUTO_TILE) {
uint16_t mask = 0;
if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_2X2) {
if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
@@ -760,16 +845,37 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) {
if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
mask |= TileSet::BIND_BOTTOMRIGHT;
}
- } else if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3) {
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_TOPLEFT;
+ } else {
+ if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3_MINIMAL) {
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
+ mask |= TileSet::BIND_TOPLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
+ mask |= TileSet::BIND_TOPRIGHT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
+ mask |= TileSet::BIND_BOTTOMLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
+ mask |= TileSet::BIND_BOTTOMRIGHT;
+ }
+ } else {
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) {
+ mask |= TileSet::BIND_TOPLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) {
+ mask |= TileSet::BIND_TOPRIGHT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) {
+ mask |= TileSet::BIND_BOTTOMLEFT;
+ }
+ if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) {
+ mask |= TileSet::BIND_BOTTOMRIGHT;
+ }
}
if (tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1))) {
mask |= TileSet::BIND_TOP;
}
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_TOPRIGHT;
- }
if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
mask |= TileSet::BIND_LEFT;
}
@@ -777,15 +883,9 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) {
if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
mask |= TileSet::BIND_RIGHT;
}
- if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) {
- mask |= TileSet::BIND_BOTTOMLEFT;
- }
if (tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1))) {
mask |= TileSet::BIND_BOTTOM;
}
- if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) {
- mask |= TileSet::BIND_BOTTOMRIGHT;
- }
}
Vector2 coord = tile_set->autotile_get_subtile_for_bitmask(id, mask, this, Vector2(p_x, p_y));
E->get().autotile_coord_x = (int)coord.x;
@@ -809,6 +909,16 @@ void TileMap::update_dirty_bitmask() {
}
}
+void TileMap::fix_invalid_tiles() {
+
+ for (Map<PosKey, Cell>::Element *E = tile_map.front(); E; E = E->next()) {
+
+ if (!tile_set->has_tile(get_cell(E->key().x, E->key().y))) {
+ set_cell(E->key().x, E->key().y, INVALID_CELL);
+ }
+ }
+}
+
int TileMap::get_cell(int p_x, int p_y) const {
PosKey pk(p_x, p_y);
@@ -978,8 +1088,8 @@ void TileMap::_set_tile_data(const PoolVector<int> &p_data) {
bool flip_v = v & (1 << 30);
bool transpose = v & (1 << 31);
v &= (1 << 29) - 1;
- int16_t coord_x;
- int16_t coord_y;
+ int16_t coord_x = 0;
+ int16_t coord_y = 0;
if (format == FORMAT_2) {
coord_x = decode_uint16(&local[8]);
coord_y = decode_uint16(&local[10]);
@@ -1029,6 +1139,10 @@ Rect2 TileMap::_edit_get_rect() const {
return rect_cache;
}
+bool TileMap::_edit_use_rect() const {
+ return true;
+}
+
void TileMap::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
@@ -1291,10 +1405,10 @@ bool TileMap::_get(const StringName &p_name, Variant &r_ret) const {
void TileMap::_get_property_list(List<PropertyInfo> *p_list) const {
- PropertyInfo p(Variant::INT, "format", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ PropertyInfo p(Variant::INT, "format", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL);
p_list->push_back(p);
- p = PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR);
+ p = PropertyInfo(Variant::OBJECT, "tile_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL);
p_list->push_back(p);
}
@@ -1494,6 +1608,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_cell_y_flipped", "x", "y"), &TileMap::is_cell_y_flipped);
ClassDB::bind_method(D_METHOD("is_cell_transposed", "x", "y"), &TileMap::is_cell_transposed);
+ ClassDB::bind_method(D_METHOD("fix_invalid_tiles"), &TileMap::fix_invalid_tiles);
ClassDB::bind_method(D_METHOD("clear"), &TileMap::clear);
ClassDB::bind_method(D_METHOD("get_used_cells"), &TileMap::get_used_cells);
@@ -1507,6 +1622,9 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_recreate_quadrants"), &TileMap::_recreate_quadrants);
ClassDB::bind_method(D_METHOD("_update_dirty_quadrants"), &TileMap::_update_dirty_quadrants);
+ ClassDB::bind_method(D_METHOD("update_bitmask_area", "position"), &TileMap::update_bitmask_area);
+ ClassDB::bind_method(D_METHOD("update_bitmask_region", "start", "end"), &TileMap::update_bitmask_region, DEFVAL(Vector2()), DEFVAL(Vector2()));
+
ClassDB::bind_method(D_METHOD("_set_tile_data"), &TileMap::_set_tile_data);
ClassDB::bind_method(D_METHOD("_get_tile_data"), &TileMap::_get_tile_data);
@@ -1549,6 +1667,12 @@ void TileMap::_bind_methods() {
BIND_ENUM_CONSTANT(TILE_ORIGIN_BOTTOM_LEFT);
}
+void TileMap::_changed_callback(Object *p_changed, const char *p_prop) {
+ if (tile_set.is_valid() && tile_set.ptr() == p_changed) {
+ emit_signal("settings_changed");
+ }
+}
+
TileMap::TileMap() {
rect_cache_dirty = true;
@@ -1577,5 +1701,8 @@ TileMap::TileMap() {
TileMap::~TileMap() {
+ if (tile_set.is_valid())
+ tile_set->remove_change_receptor(this);
+
clear();
}
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index e5608884c4..07947004b3 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TILE_MAP_H
#define TILE_MAP_H
@@ -216,6 +217,8 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ virtual void _changed_callback(Object *p_changed, const char *p_prop);
+
public:
enum {
INVALID_CELL = -1
@@ -242,9 +245,11 @@ public:
int get_cellv(const Vector2 &p_pos) const;
Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
void make_bitmask_area_dirty(const Vector2 &p_pos);
void update_bitmask_area(const Vector2 &p_pos);
+ void update_bitmask_region(const Vector2 &p_start = Vector2(), const Vector2 &p_end = Vector2());
void update_cell_bitmask(int p_x, int p_y);
void update_dirty_bitmask();
@@ -306,6 +311,7 @@ public:
void set_clip_uv(bool p_enable);
bool get_clip_uv() const;
+ void fix_invalid_tiles();
void clear();
TileMap();
diff --git a/scene/2d/visibility_notifier_2d.cpp b/scene/2d/visibility_notifier_2d.cpp
index 298bc2649e..ddca97e60a 100644
--- a/scene/2d/visibility_notifier_2d.cpp
+++ b/scene/2d/visibility_notifier_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "visibility_notifier_2d.h"
#include "engine.h"
@@ -88,6 +89,10 @@ Rect2 VisibilityNotifier2D::_edit_get_rect() const {
return rect;
}
+bool VisibilityNotifier2D::_edit_use_rect() const {
+ return true;
+}
+
Rect2 VisibilityNotifier2D::get_rect() const {
return rect;
@@ -218,7 +223,7 @@ void VisibilityEnabler2D::_find_nodes(Node *p_node) {
if (add) {
- p_node->connect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed", varray(p_node), CONNECT_ONESHOT);
+ p_node->connect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed", varray(p_node), CONNECT_ONESHOT);
nodes[p_node] = meta;
_change_node_state(p_node, false);
}
@@ -261,7 +266,7 @@ void VisibilityEnabler2D::_notification(int p_what) {
if (!visible)
_change_node_state(E->key(), true);
- E->key()->disconnect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed");
+ E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed");
}
nodes.clear();
diff --git a/scene/2d/visibility_notifier_2d.h b/scene/2d/visibility_notifier_2d.h
index 6e06833912..c4e12dfa22 100644
--- a/scene/2d/visibility_notifier_2d.h
+++ b/scene/2d/visibility_notifier_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VISIBILITY_NOTIFIER_2D_H
#define VISIBILITY_NOTIFIER_2D_H
@@ -55,6 +56,7 @@ protected:
public:
virtual Rect2 _edit_get_rect() const;
+ virtual bool _edit_use_rect() const;
void set_rect(const Rect2 &p_rect);
Rect2 get_rect() const;
diff --git a/scene/2d/y_sort.cpp b/scene/2d/y_sort.cpp
index e0fb3f0645..d3997c13c3 100644
--- a/scene/2d/y_sort.cpp
+++ b/scene/2d/y_sort.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "y_sort.h"
void YSort::set_sort_enabled(bool p_enabled) {
diff --git a/scene/2d/y_sort.h b/scene/2d/y_sort.h
index de7aa3a317..5ff12aa25a 100644
--- a/scene/2d/y_sort.h
+++ b/scene/2d/y_sort.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef Y_SORT_H
#define Y_SORT_H
diff --git a/scene/3d/area.cpp b/scene/3d/area.cpp
index 422aa556f9..6ea980ec97 100644
--- a/scene/3d/area.cpp
+++ b/scene/3d/area.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "area.h"
#include "scene/scene_string_names.h"
#include "servers/audio_server.h"
@@ -168,7 +169,7 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -195,7 +196,7 @@ void Area::_body_inout(int p_status, const RID &p_body, int p_instance, int p_bo
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (E->get().in_tree)
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
}
@@ -245,7 +246,7 @@ void Area::_clear_monitoring() {
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
}
}
@@ -275,7 +276,7 @@ void Area::_clear_monitoring() {
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree);
}
}
}
@@ -365,7 +366,7 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree, make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_entered, node);
}
@@ -392,7 +393,7 @@ void Area::_area_inout(int p_status, const RID &p_area, int p_instance, int p_ar
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_area_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_area_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_area_exit_tree);
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->area_exited, obj);
}
@@ -710,7 +711,7 @@ void Area::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "space_override", PROPERTY_HINT_ENUM, "Disabled,Combine,Combine-Replace,Replace,Replace-Combine"), "set_space_override_mode", "get_space_override_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "gravity_point"), "set_gravity_is_point", "is_gravity_a_point");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_gravity_distance_scale", "get_gravity_distance_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_distance_scale", PROPERTY_HINT_EXP_RANGE, "0,1024,0.001,or_greater"), "set_gravity_distance_scale", "get_gravity_distance_scale");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity_vec"), "set_gravity_vector", "get_gravity_vector");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_gravity", "get_gravity");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "linear_damp", PROPERTY_HINT_RANGE, "0,1024,0.001"), "set_linear_damp", "get_linear_damp");
diff --git a/scene/3d/area.h b/scene/3d/area.h
index 7ea97d0a8c..e49b7e493b 100644
--- a/scene/3d/area.h
+++ b/scene/3d/area.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef AREA_H
#define AREA_H
diff --git a/scene/3d/arvr_nodes.cpp b/scene/3d/arvr_nodes.cpp
index e1e0b9b1ce..001c58ea76 100644
--- a/scene/3d/arvr_nodes.cpp
+++ b/scene/3d/arvr_nodes.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -231,7 +231,7 @@ void ARVRController::_notification(int p_what) {
void ARVRController::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &ARVRController::set_controller_id);
ClassDB::bind_method(D_METHOD("get_controller_id"), &ARVRController::get_controller_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "1,32,1"), "set_controller_id", "get_controller_id");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id");
ClassDB::bind_method(D_METHOD("get_controller_name"), &ARVRController::get_controller_name);
// passthroughs to information about our related joystick
@@ -251,7 +251,8 @@ void ARVRController::_bind_methods() {
};
void ARVRController::set_controller_id(int p_controller_id) {
- // we don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
+ // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
+ // Note that setting this to 0 means this node is not bound to a controller yet.
controller_id = p_controller_id;
};
@@ -420,7 +421,7 @@ void ARVRAnchor::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &ARVRAnchor::set_anchor_id);
ClassDB::bind_method(D_METHOD("get_anchor_id"), &ARVRAnchor::get_anchor_id);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id"), "set_anchor_id", "get_anchor_id");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id");
ClassDB::bind_method(D_METHOD("get_anchor_name"), &ARVRAnchor::get_anchor_name);
ClassDB::bind_method(D_METHOD("get_is_active"), &ARVRAnchor::get_is_active);
@@ -430,7 +431,8 @@ void ARVRAnchor::_bind_methods() {
};
void ARVRAnchor::set_anchor_id(int p_anchor_id) {
- // we don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
+ // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
+ // Note that setting this to 0 means this node is not bound to an anchor yet.
anchor_id = p_anchor_id;
};
diff --git a/scene/3d/arvr_nodes.h b/scene/3d/arvr_nodes.h
index 6e940351f2..67fb658562 100644
--- a/scene/3d/arvr_nodes.h
+++ b/scene/3d/arvr_nodes.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 6c102e4027..e7b3645001 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* audio_stream_player_3d.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "audio_stream_player_3d.h"
#include "engine.h"
#include "scene/3d/area.h"
@@ -27,18 +57,18 @@ void AudioStreamPlayer3D::_mix_audio() {
//mix
if (output_count > 0 || out_of_range_mode == OUT_OF_RANGE_MIX) {
- float pitch_scale = 0.0;
+ float output_pitch_scale = 0.0;
if (output_count) {
//used for doppler, not realistic but good enough
for (int i = 0; i < output_count; i++) {
- pitch_scale += outputs[i].pitch_scale;
+ output_pitch_scale += outputs[i].pitch_scale;
}
- pitch_scale /= float(output_count);
+ output_pitch_scale /= float(output_count);
} else {
- pitch_scale = 1.0;
+ output_pitch_scale = 1.0;
}
- stream_playback->mix(buffer, pitch_scale, buffer_size);
+ stream_playback->mix(buffer, pitch_scale * output_pitch_scale, buffer_size);
}
//write all outputs
@@ -290,7 +320,7 @@ void AudioStreamPlayer3D::_notification(int p_what) {
total_max = MAX(total_max, cam_area_pos.length());
}
if (total_max > max_distance) {
- continue; //cant hear this sound in this camera
+ continue; //can't hear this sound in this camera
}
}
@@ -506,14 +536,14 @@ void AudioStreamPlayer3D::_notification(int p_what) {
setseek = setplay;
active = true;
setplay = -1;
- //do not update, this makes it easier to animate (will shut off otherise)
+ //do not update, this makes it easier to animate (will shut off otherwise)
///_change_notify("playing"); //update property in editor
}
//stop playing if no longer active
if (!active) {
set_physics_process_internal(false);
- //do not update, this makes it easier to animate (will shut off otherise)
+ //do not update, this makes it easier to animate (will shut off otherwise)
//_change_notify("playing"); //update property in editor
emit_signal("finished");
}
@@ -577,6 +607,13 @@ float AudioStreamPlayer3D::get_max_db() const {
return max_db;
}
+void AudioStreamPlayer3D::set_pitch_scale(float p_pitch_scale) {
+ pitch_scale = p_pitch_scale;
+}
+float AudioStreamPlayer3D::get_pitch_scale() const {
+ return pitch_scale;
+}
+
void AudioStreamPlayer3D::play(float p_from_pos) {
if (stream_playback.is_valid()) {
@@ -802,6 +839,9 @@ void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_max_db", "max_db"), &AudioStreamPlayer3D::set_max_db);
ClassDB::bind_method(D_METHOD("get_max_db"), &AudioStreamPlayer3D::get_max_db);
+ ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer3D::set_pitch_scale);
+ ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer3D::get_pitch_scale);
+
ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer3D::play, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer3D::seek);
ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer3D::stop);
@@ -855,9 +895,10 @@ void AudioStreamPlayer3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.1"), "set_unit_size", "get_unit_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,65536,1"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,4096,1,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::INT, "out_of_range_mode", PROPERTY_HINT_ENUM, "Mix,Pause"), "set_out_of_range_mode", "get_out_of_range_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask");
@@ -891,6 +932,7 @@ AudioStreamPlayer3D::AudioStreamPlayer3D() {
unit_size = 1;
attenuation_model = ATTENUATION_INVERSE_DISTANCE;
max_db = 3;
+ pitch_scale = 1.0;
autoplay = false;
setseek = -1;
active = false;
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index 5982d7a3ac..1fcb83cf21 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* audio_stream_player_3d.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 AUDIO_STREAM_PLAYER_3D_H
#define AUDIO_STREAM_PLAYER_3D_H
@@ -76,6 +106,7 @@ private:
float unit_db;
float unit_size;
float max_db;
+ float pitch_scale;
bool autoplay;
StringName bus;
@@ -123,6 +154,9 @@ public:
void set_max_db(float p_boost);
float get_max_db() const;
+ void set_pitch_scale(float p_pitch_scale);
+ float get_pitch_scale() const;
+
void play(float p_from_pos = 0.0);
void seek(float p_seconds);
void stop();
diff --git a/scene/3d/baked_lightmap.cpp b/scene/3d/baked_lightmap.cpp
index 8af8c2f7da..204aaef7ec 100644
--- a/scene/3d/baked_lightmap.cpp
+++ b/scene/3d/baked_lightmap.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* baked_lightmap.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "baked_lightmap.h"
#include "io/resource_saver.h"
#include "os/dir_access.h"
@@ -55,12 +85,13 @@ float BakedLightmapData::get_energy() const {
return energy;
}
-void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap) {
+void BakedLightmapData::add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance) {
ERR_FAIL_COND(p_lightmap.is_null());
User user;
user.path = p_path;
user.lightmap = p_lightmap;
+ user.instance_index = p_instance;
users.push_back(user);
}
@@ -79,16 +110,22 @@ Ref<Texture> BakedLightmapData::get_user_lightmap(int p_user) const {
return users[p_user].lightmap;
}
+int BakedLightmapData::get_user_instance(int p_user) const {
+
+ ERR_FAIL_INDEX_V(p_user, users.size(), -1);
+ return users[p_user].instance_index;
+}
+
void BakedLightmapData::clear_users() {
users.clear();
}
void BakedLightmapData::_set_user_data(const Array &p_data) {
- ERR_FAIL_COND(p_data.size() & 1);
+ ERR_FAIL_COND((p_data.size() % 3) != 0);
- for (int i = 0; i < p_data.size(); i += 2) {
- add_user(p_data[i], p_data[i + 1]);
+ for (int i = 0; i < p_data.size(); i += 3) {
+ add_user(p_data[i], p_data[i + 1], p_data[i + 2]);
}
}
@@ -98,6 +135,7 @@ Array BakedLightmapData::_get_user_data() const {
for (int i = 0; i < users.size(); i++) {
ret.push_back(users[i].path);
ret.push_back(users[i].lightmap);
+ ret.push_back(users[i].instance_index);
}
return ret;
}
@@ -125,18 +163,18 @@ void BakedLightmapData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_energy", "energy"), &BakedLightmapData::set_energy);
ClassDB::bind_method(D_METHOD("get_energy"), &BakedLightmapData::get_energy);
- ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap"), &BakedLightmapData::add_user);
+ ClassDB::bind_method(D_METHOD("add_user", "path", "lightmap", "instance"), &BakedLightmapData::add_user);
ClassDB::bind_method(D_METHOD("get_user_count"), &BakedLightmapData::get_user_count);
ClassDB::bind_method(D_METHOD("get_user_path", "user_idx"), &BakedLightmapData::get_user_path);
ClassDB::bind_method(D_METHOD("get_user_lightmap", "user_idx"), &BakedLightmapData::get_user_lightmap);
ClassDB::bind_method(D_METHOD("clear_users"), &BakedLightmapData::clear_users);
ADD_PROPERTY(PropertyInfo(Variant::AABB, "bounds", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_bounds", "get_bounds");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree");
ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "cell_space_transform", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_space_transform", "get_cell_space_transform");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cell_subdiv", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_cell_subdiv", "get_cell_subdiv");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_energy", "get_energy");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_user_data", "_get_user_data");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "octree", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_octree", "get_octree");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "user_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_user_data", "_get_user_data");
}
BakedLightmapData::BakedLightmapData() {
@@ -157,24 +195,25 @@ BakedLightmap::BakeBeginFunc BakedLightmap::bake_begin_function = NULL;
BakedLightmap::BakeStepFunc BakedLightmap::bake_step_function = NULL;
BakedLightmap::BakeEndFunc BakedLightmap::bake_end_function = NULL;
-void BakedLightmap::set_bake_subdiv(Subdiv p_subdiv) {
- bake_subdiv = p_subdiv;
+void BakedLightmap::set_bake_cell_size(float p_cell_size) {
+ bake_cell_size = p_cell_size;
}
-BakedLightmap::Subdiv BakedLightmap::get_bake_subdiv() const {
- return bake_subdiv;
+float BakedLightmap::get_bake_cell_size() const {
+ return bake_cell_size;
}
-void BakedLightmap::set_capture_subdiv(Subdiv p_subdiv) {
- capture_subdiv = p_subdiv;
+void BakedLightmap::set_capture_cell_size(float p_cell_size) {
+ capture_cell_size = p_cell_size;
}
-BakedLightmap::Subdiv BakedLightmap::get_capture_subdiv() const {
- return capture_subdiv;
+float BakedLightmap::get_capture_cell_size() const {
+ return capture_cell_size;
}
void BakedLightmap::set_extents(const Vector3 &p_extents) {
extents = p_extents;
+ update_gizmo();
}
Vector3 BakedLightmap::get_extents() const {
@@ -208,6 +247,7 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo
pm.local_xform = xf;
pm.mesh = mesh;
pm.path = get_path_to(mi);
+ pm.instance_idx = -1;
for (int i = 0; i < mesh->get_surface_count(); i++) {
pm.instance_materials.push_back(mi->get_surface_material(i));
}
@@ -218,6 +258,26 @@ void BakedLightmap::_find_meshes_and_lights(Node *p_at_node, List<PlotMesh> &plo
}
}
+ Spatial *s = Object::cast_to<Spatial>(p_at_node);
+
+ if (!mi && s) {
+ Array meshes = p_at_node->call("get_bake_meshes");
+ if (meshes.size() && (meshes.size() & 1) == 0) {
+ Transform xf = get_global_transform().affine_inverse() * s->get_global_transform();
+ for (int i = 0; i < meshes.size(); i += 2) {
+ PlotMesh pm;
+ Transform mesh_xf = meshes[i + 1];
+ pm.local_xform = xf * mesh_xf;
+ pm.mesh = meshes[i];
+ pm.instance_idx = i / 2;
+ if (!pm.mesh.is_valid())
+ continue;
+ pm.path = get_path_to(s);
+ plot_meshes.push_back(pm);
+ }
+ }
+ }
+
Light *light = Object::cast_to<Light>(p_at_node);
if (light && light->get_bake_mode() != Light::BAKE_DISABLED) {
@@ -256,7 +316,7 @@ bool BakedLightmap::_bake_time(void *ud, float p_secs, float p_progress) {
int mins_left = p_secs / 60;
int secs_left = Math::fmod(p_secs, 60.0f);
int percent = p_progress * 100;
- bool abort = bake_step_function(btd->pass + percent, btd->text + " " + itos(percent) + "% (Time Left: " + itos(mins_left) + ":" + itos(secs_left) + "s)");
+ bool abort = bake_step_function(btd->pass + percent, btd->text + " " + vformat(RTR("%d%%"), percent) + " " + vformat(RTR("(Time Left: %d:%02d s)"), mins_left, secs_left));
btd->last_step = time;
if (abort)
return true;
@@ -297,11 +357,29 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
Ref<BakedLightmapData> new_light_data;
new_light_data.instance();
- static const int subdiv_value[SUBDIV_MAX] = { 8, 9, 10, 11, 12, 13 };
-
VoxelLightBaker baker;
- baker.begin_bake(subdiv_value[bake_subdiv], AABB(-extents, extents * 2.0));
+ int bake_subdiv;
+ int capture_subdiv;
+ AABB bake_bounds;
+ {
+ bake_bounds = AABB(-extents, extents * 2.0);
+ int subdiv = nearest_power_of_2_templated(int(bake_bounds.get_longest_axis_size() / bake_cell_size));
+ bake_bounds.size[bake_bounds.get_longest_axis_size()] = subdiv * bake_cell_size;
+ bake_subdiv = nearest_shift(subdiv) + 1;
+
+ capture_subdiv = bake_subdiv;
+ float css = bake_cell_size;
+ while (css < capture_cell_size && capture_subdiv > 2) {
+ capture_subdiv--;
+ css *= 2.0;
+ }
+
+ print_line("bake subdiv: " + itos(bake_subdiv));
+ print_line("capture subdiv: " + itos(capture_subdiv));
+ }
+
+ baker.begin_bake(bake_subdiv, bake_bounds);
List<PlotMesh> mesh_list;
List<PlotLight> light_list;
@@ -476,23 +554,23 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, bool p_create_vi
if (set_path) {
tex->set_path(image_path);
}
- new_light_data->add_user(E->get().path, tex);
+ new_light_data->add_user(E->get().path, tex, E->get().instance_idx);
}
}
- int csubdiv = subdiv_value[capture_subdiv];
AABB bounds = AABB(-extents, extents * 2);
- new_light_data->set_cell_subdiv(csubdiv);
+ new_light_data->set_cell_subdiv(capture_subdiv);
new_light_data->set_bounds(bounds);
- new_light_data->set_octree(baker.create_capture_octree(csubdiv));
+ new_light_data->set_octree(baker.create_capture_octree(capture_subdiv));
{
+ float bake_bound_size = bake_bounds.get_longest_axis_size();
Transform to_bounds;
- to_bounds.basis.scale(Vector3(bounds.get_longest_axis_size(), bounds.get_longest_axis_size(), bounds.get_longest_axis_size()));
+ to_bounds.basis.scale(Vector3(bake_bound_size, bake_bound_size, bake_bound_size));
to_bounds.origin = bounds.position;
Transform to_grid;
- to_grid.basis.scale(Vector3(1 << (csubdiv - 1), 1 << (csubdiv - 1), 1 << (csubdiv - 1)));
+ to_grid.basis.scale(Vector3(1 << (capture_subdiv - 1), 1 << (capture_subdiv - 1), 1 << (capture_subdiv - 1)));
Transform to_cell_space = to_grid * to_bounds.affine_inverse();
new_light_data->set_cell_space_transform(to_cell_space);
@@ -546,12 +624,21 @@ void BakedLightmap::_assign_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
- Node *node = get_node(light_data->get_user_path(i));
- VisualInstance *vi = Object::cast_to<VisualInstance>(node);
- ERR_CONTINUE(!vi);
Ref<Texture> lightmap = light_data->get_user_lightmap(i);
ERR_CONTINUE(!lightmap.is_valid());
- VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
+
+ Node *node = get_node(light_data->get_user_path(i));
+ int instance_idx = light_data->get_user_instance(i);
+ if (instance_idx >= 0) {
+ RID instance = node->call("get_bake_mesh_instance", instance_idx);
+ if (instance.is_valid()) {
+ VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), lightmap->get_rid());
+ }
+ } else {
+ VisualInstance *vi = Object::cast_to<VisualInstance>(node);
+ ERR_CONTINUE(!vi);
+ VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), lightmap->get_rid());
+ }
}
}
@@ -559,9 +646,17 @@ void BakedLightmap::_clear_lightmaps() {
ERR_FAIL_COND(!light_data.is_valid());
for (int i = 0; i < light_data->get_user_count(); i++) {
Node *node = get_node(light_data->get_user_path(i));
- VisualInstance *vi = Object::cast_to<VisualInstance>(node);
- ERR_CONTINUE(!vi);
- VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), RID(), RID());
+ int instance_idx = light_data->get_user_instance(i);
+ if (instance_idx >= 0) {
+ RID instance = node->call("get_bake_mesh_instance", instance_idx);
+ if (instance.is_valid()) {
+ VS::get_singleton()->instance_set_use_lightmap(instance, get_instance(), RID());
+ }
+ } else {
+ VisualInstance *vi = Object::cast_to<VisualInstance>(node);
+ ERR_CONTINUE(!vi);
+ VS::get_singleton()->instance_set_use_lightmap(vi->get_instance(), get_instance(), RID());
+ }
}
}
@@ -646,11 +741,11 @@ void BakedLightmap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_light_data", "data"), &BakedLightmap::set_light_data);
ClassDB::bind_method(D_METHOD("get_light_data"), &BakedLightmap::get_light_data);
- ClassDB::bind_method(D_METHOD("set_bake_subdiv", "bake_subdiv"), &BakedLightmap::set_bake_subdiv);
- ClassDB::bind_method(D_METHOD("get_bake_subdiv"), &BakedLightmap::get_bake_subdiv);
+ ClassDB::bind_method(D_METHOD("set_bake_cell_size", "bake_cell_size"), &BakedLightmap::set_bake_cell_size);
+ ClassDB::bind_method(D_METHOD("get_bake_cell_size"), &BakedLightmap::get_bake_cell_size);
- ClassDB::bind_method(D_METHOD("set_capture_subdiv", "capture_subdiv"), &BakedLightmap::set_capture_subdiv);
- ClassDB::bind_method(D_METHOD("get_capture_subdiv"), &BakedLightmap::get_capture_subdiv);
+ ClassDB::bind_method(D_METHOD("set_capture_cell_size", "capture_cell_size"), &BakedLightmap::set_capture_cell_size);
+ ClassDB::bind_method(D_METHOD("get_capture_cell_size"), &BakedLightmap::get_capture_cell_size);
ClassDB::bind_method(D_METHOD("set_bake_quality", "bake_quality"), &BakedLightmap::set_bake_quality);
ClassDB::bind_method(D_METHOD("get_bake_quality"), &BakedLightmap::get_bake_quality);
@@ -677,37 +772,39 @@ void BakedLightmap::_bind_methods() {
ClassDB::bind_method(D_METHOD("debug_bake"), &BakedLightmap::_debug_bake);
ClassDB::set_method_flags(get_class_static(), _scs_create("debug_bake"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_subdiv", PROPERTY_HINT_ENUM, "128,256,512,1024,2048,4096"), "set_bake_subdiv", "get_bake_subdiv");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "capture_subdiv", PROPERTY_HINT_ENUM, "128,256,512"), "set_capture_subdiv", "get_capture_subdiv");
+ ADD_GROUP("Bake", "bake_");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_bake_cell_size", "get_bake_cell_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_quality", PROPERTY_HINT_ENUM, "Low,Medium,High"), "set_bake_quality", "get_bake_quality");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_mode", PROPERTY_HINT_ENUM, "ConeTrace,RayTrace"), "set_bake_mode", "get_bake_mode");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "is_hdr");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_propagation", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_propagation", "get_propagation");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_energy", PROPERTY_HINT_RANGE, "0,32,0.01"), "set_energy", "get_energy");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bake_hdr"), "set_hdr", "is_hdr");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "bake_extents"), "set_extents", "get_extents");
+ ADD_GROUP("Capture", "capture_");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "capture_cell_size", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_capture_cell_size", "get_capture_cell_size");
+ ADD_GROUP("Data", "");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_path", PROPERTY_HINT_DIR), "set_image_path", "get_image_path");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "extents"), "set_extents", "get_extents");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedIndirectLightData"), "set_light_data", "get_light_data");
-
- BIND_ENUM_CONSTANT(SUBDIV_128);
- BIND_ENUM_CONSTANT(SUBDIV_256);
- BIND_ENUM_CONSTANT(SUBDIV_512);
- BIND_ENUM_CONSTANT(SUBDIV_1024);
- BIND_ENUM_CONSTANT(SUBDIV_2048);
- BIND_ENUM_CONSTANT(SUBDIV_4096);
- BIND_ENUM_CONSTANT(SUBDIV_MAX);
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "light_data", PROPERTY_HINT_RESOURCE_TYPE, "BakedLightmapData"), "set_light_data", "get_light_data");
BIND_ENUM_CONSTANT(BAKE_QUALITY_LOW);
BIND_ENUM_CONSTANT(BAKE_QUALITY_MEDIUM);
BIND_ENUM_CONSTANT(BAKE_QUALITY_HIGH);
BIND_ENUM_CONSTANT(BAKE_MODE_CONE_TRACE);
BIND_ENUM_CONSTANT(BAKE_MODE_RAY_TRACE);
+
+ BIND_ENUM_CONSTANT(BAKE_ERROR_OK);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_NO_SAVE_PATH);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_NO_MESHES);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_CANT_CREATE_IMAGE);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_USER_ABORTED);
}
BakedLightmap::BakedLightmap() {
extents = Vector3(10, 10, 10);
- bake_subdiv = SUBDIV_256;
- capture_subdiv = SUBDIV_128;
+ bake_cell_size = 0.25;
+ capture_cell_size = 0.5;
+
bake_quality = BAKE_QUALITY_MEDIUM;
bake_mode = BAKE_MODE_CONE_TRACE;
energy = 1;
diff --git a/scene/3d/baked_lightmap.h b/scene/3d/baked_lightmap.h
index 5595ec1e61..60b62f74eb 100644
--- a/scene/3d/baked_lightmap.h
+++ b/scene/3d/baked_lightmap.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* baked_lightmap.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 BAKED_INDIRECT_LIGHT_H
#define BAKED_INDIRECT_LIGHT_H
@@ -18,6 +48,7 @@ class BakedLightmapData : public Resource {
NodePath path;
Ref<Texture> lightmap;
+ int instance_index;
};
Vector<User> users;
@@ -44,10 +75,11 @@ public:
void set_energy(float p_energy);
float get_energy() const;
- void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap);
+ void add_user(const NodePath &p_path, const Ref<Texture> &p_lightmap, int p_instance = -1);
int get_user_count() const;
NodePath get_user_path(int p_user) const;
Ref<Texture> get_user_lightmap(int p_user) const;
+ int get_user_instance(int p_user) const;
void clear_users();
virtual RID get_rid() const;
@@ -59,17 +91,6 @@ class BakedLightmap : public VisualInstance {
GDCLASS(BakedLightmap, VisualInstance);
public:
- enum Subdiv {
- SUBDIV_128,
- SUBDIV_256,
- SUBDIV_512,
- SUBDIV_1024,
- SUBDIV_2048,
- SUBDIV_4096,
- SUBDIV_MAX
-
- };
-
enum BakeQuality {
BAKE_QUALITY_LOW,
BAKE_QUALITY_MEDIUM,
@@ -95,8 +116,8 @@ public:
typedef void (*BakeEndFunc)();
private:
- Subdiv bake_subdiv;
- Subdiv capture_subdiv;
+ float bake_cell_size;
+ float capture_cell_size;
Vector3 extents;
float propagation;
float energy;
@@ -113,6 +134,7 @@ private:
Ref<Mesh> mesh;
Transform local_xform;
NodePath path;
+ int instance_idx;
};
struct PlotLight {
@@ -147,11 +169,11 @@ public:
void set_light_data(const Ref<BakedLightmapData> &p_data);
Ref<BakedLightmapData> get_light_data() const;
- void set_bake_subdiv(Subdiv p_subdiv);
- Subdiv get_bake_subdiv() const;
+ void set_bake_cell_size(float p_cell_size);
+ float get_bake_cell_size() const;
- void set_capture_subdiv(Subdiv p_subdiv);
- Subdiv get_capture_subdiv() const;
+ void set_capture_cell_size(float p_cell_size);
+ float get_capture_cell_size() const;
void set_extents(const Vector3 &p_extents);
Vector3 get_extents() const;
@@ -181,7 +203,6 @@ public:
BakedLightmap();
};
-VARIANT_ENUM_CAST(BakedLightmap::Subdiv);
VARIANT_ENUM_CAST(BakedLightmap::BakeQuality);
VARIANT_ENUM_CAST(BakedLightmap::BakeMode);
VARIANT_ENUM_CAST(BakedLightmap::BakeError);
diff --git a/scene/3d/bone_attachment.cpp b/scene/3d/bone_attachment.cpp
index 2580b645e2..a875b65c22 100644
--- a/scene/3d/bone_attachment.cpp
+++ b/scene/3d/bone_attachment.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,45 +27,30 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "bone_attachment.h"
-
-bool BoneAttachment::_get(const StringName &p_name, Variant &r_ret) const {
- if (String(p_name) == "bone_name") {
-
- r_ret = get_bone_name();
- return true;
- }
+#include "bone_attachment.h"
- return false;
-}
-bool BoneAttachment::_set(const StringName &p_name, const Variant &p_value) {
+void BoneAttachment::_validate_property(PropertyInfo &property) const {
- if (String(p_name) == "bone_name") {
+ if (property.name == "bone_name") {
+ Skeleton *parent = Object::cast_to<Skeleton>(get_parent());
- set_bone_name(p_value);
- return true;
- }
+ if (parent) {
- return false;
-}
-void BoneAttachment::_get_property_list(List<PropertyInfo> *p_list) const {
-
- Skeleton *parent = Object::cast_to<Skeleton>(get_parent());
+ String names;
+ for (int i = 0; i < parent->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += parent->get_bone_name(i);
+ }
- if (parent) {
+ property.hint = PROPERTY_HINT_ENUM;
+ property.hint_string = names;
+ } else {
- String names;
- for (int i = 0; i < parent->get_bone_count(); i++) {
- if (i > 0)
- names += ",";
- names += parent->get_bone_name(i);
+ property.hint = PROPERTY_HINT_NONE;
+ property.hint_string = "";
}
-
- p_list->push_back(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM, names));
- } else {
-
- p_list->push_back(PropertyInfo(Variant::STRING, "bone_name"));
}
}
@@ -137,4 +122,6 @@ BoneAttachment::BoneAttachment() {
void BoneAttachment::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_name", "bone_name"), &BoneAttachment::set_bone_name);
ClassDB::bind_method(D_METHOD("get_bone_name"), &BoneAttachment::get_bone_name);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "bone_name"), "set_bone_name", "get_bone_name");
}
diff --git a/scene/3d/bone_attachment.h b/scene/3d/bone_attachment.h
index 159d16157a..81a225015e 100644
--- a/scene/3d/bone_attachment.h
+++ b/scene/3d/bone_attachment.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BONE_ATTACHMENT_H
#define BONE_ATTACHMENT_H
@@ -43,9 +44,7 @@ class BoneAttachment : public Spatial {
void _check_unbind();
protected:
- bool _get(const StringName &p_name, Variant &r_ret) const;
- bool _set(const StringName &p_name, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
+ virtual void _validate_property(PropertyInfo &property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/camera.cpp b/scene/3d/camera.cpp
index af210fff1c..e11e8abe5b 100644
--- a/scene/3d/camera.cpp
+++ b/scene/3d/camera.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "camera.h"
#include "camera_matrix.h"
@@ -56,130 +57,23 @@ void Camera::_update_camera_mode() {
}
}
-bool Camera::_set(const StringName &p_name, const Variant &p_value) {
-
- bool changed_all = false;
- if (p_name == "projection") {
-
- int proj = p_value;
- if (proj == PROJECTION_PERSPECTIVE)
- mode = PROJECTION_PERSPECTIVE;
- if (proj == PROJECTION_ORTHOGONAL)
- mode = PROJECTION_ORTHOGONAL;
-
- changed_all = true;
- } else if (p_name == "fov" || p_name == "fovy" || p_name == "fovx")
- fov = p_value;
- else if (p_name == "size" || p_name == "sizex" || p_name == "sizey")
- size = p_value;
- else if (p_name == "near")
- near = p_value;
- else if (p_name == "far")
- far = p_value;
- else if (p_name == "keep_aspect")
- 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();
- } else {
- clear_current();
+void Camera::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "fov") {
+ if (mode == PROJECTION_ORTHOGONAL) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
- } else if (p_name == "cull_mask") {
- set_cull_mask(p_value);
- } else if (p_name == "environment") {
- set_environment(p_value);
- } else if (p_name == "doppler/tracking") {
- set_doppler_tracking(DopplerTracking(int(p_value)));
- } else
- return false;
-
- _update_camera_mode();
- if (changed_all)
- _change_notify();
- return true;
-}
-bool Camera::_get(const StringName &p_name, Variant &r_ret) const {
-
- if (p_name == "projection") {
- r_ret = mode;
- } else if (p_name == "fov" || p_name == "fovy" || p_name == "fovx")
- r_ret = fov;
- else if (p_name == "size" || p_name == "sizex" || p_name == "sizey")
- r_ret = size;
- else if (p_name == "near")
- r_ret = near;
- else if (p_name == "far")
- r_ret = far;
- else if (p_name == "keep_aspect")
- r_ret = int(keep_aspect);
- else if (p_name == "current") {
-
- if (is_inside_tree() && get_tree()->is_node_being_edited(this)) {
- r_ret = current;
- } else {
- r_ret = is_current();
+ } else if (p_property.name == "size") {
+ if (mode == PROJECTION_PERSPECTIVE) {
+ p_property.usage = PROPERTY_USAGE_NOEDITOR;
}
- } else if (p_name == "cull_mask") {
- r_ret = get_cull_mask();
- } 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 if (p_name == "doppler/tracking") {
- r_ret = get_doppler_tracking();
- } else
- return false;
-
- return true;
-}
-
-void Camera::_get_property_list(List<PropertyInfo> *p_list) const {
-
- p_list->push_back(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"));
-
- switch (mode) {
-
- case PROJECTION_PERSPECTIVE: {
-
- p_list->push_back(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_NOEDITOR));
- if (keep_aspect == KEEP_WIDTH)
- p_list->push_back(PropertyInfo(Variant::REAL, "fovx", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_EDITOR));
- else
- p_list->push_back(PropertyInfo(Variant::REAL, "fovy", PROPERTY_HINT_RANGE, "1,179,0.1", PROPERTY_USAGE_EDITOR));
-
- } break;
- case PROJECTION_ORTHOGONAL: {
-
- p_list->push_back(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "1,16384,0.01", PROPERTY_USAGE_NOEDITOR));
- if (keep_aspect == KEEP_WIDTH)
- p_list->push_back(PropertyInfo(Variant::REAL, "sizex", PROPERTY_HINT_RANGE, "0.1,16384,0.01", PROPERTY_USAGE_EDITOR));
- else
- p_list->push_back(PropertyInfo(Variant::REAL, "sizey", PROPERTY_HINT_RANGE, "0.1,16384,0.01", PROPERTY_USAGE_EDITOR));
-
- } break;
}
-
- p_list->push_back(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.01,4096.0,0.01"));
- p_list->push_back(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "current"));
- p_list->push_back(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER));
- 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"));
- p_list->push_back(PropertyInfo(Variant::INT, "doppler/tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"));
}
void Camera::_update_camera() {
+ if (!is_inside_tree())
+ return;
+
Transform tr = get_camera_transform();
tr.origin += tr.basis.get_axis(1) * v_offset;
tr.origin += tr.basis.get_axis(0) * h_offset;
@@ -191,7 +85,7 @@ void Camera::_update_camera() {
get_viewport()->_camera_transform_changed_notify();
*/
- if (!is_inside_tree() || get_tree()->is_node_being_edited(this) || !is_current())
+ if (get_tree()->is_node_being_edited(this) || !is_current())
return;
get_viewport()->_camera_transform_changed_notify();
@@ -282,6 +176,14 @@ void Camera::set_orthogonal(float p_size, float p_z_near, float p_z_far) {
update_gizmo();
}
+void Camera::set_projection(Camera::Projection p_mode) {
+ if (p_mode == PROJECTION_PERSPECTIVE || p_mode == PROJECTION_ORTHOGONAL) {
+ mode = p_mode;
+ _update_camera_mode();
+ _change_notify();
+ }
+}
+
RID Camera::get_camera() const {
return camera;
@@ -299,7 +201,7 @@ void Camera::make_current() {
//get_scene()->call_group(SceneMainLoop::GROUP_CALL_REALTIME,camera_group,"_camera_make_current",this);
}
-void Camera::clear_current() {
+void Camera::clear_current(bool p_enable_next) {
current = false;
if (!is_inside_tree())
@@ -307,7 +209,18 @@ void Camera::clear_current() {
if (get_viewport()->get_camera() == this) {
get_viewport()->_camera_set(NULL);
- get_viewport()->_camera_make_next_current(this);
+
+ if (p_enable_next) {
+ get_viewport()->_camera_make_next_current(this);
+ }
+ }
+}
+
+void Camera::set_current(bool p_current) {
+ if (p_current) {
+ make_current();
+ } else {
+ clear_current();
}
}
@@ -481,6 +394,7 @@ void Camera::set_environment(const Ref<Environment> &p_environment) {
VS::get_singleton()->camera_set_environment(camera, environment->get_rid());
else
VS::get_singleton()->camera_set_environment(camera, RID());
+ _update_camera_mode();
}
Ref<Environment> Camera::get_environment() const {
@@ -489,10 +403,9 @@ Ref<Environment> Camera::get_environment() const {
}
void Camera::set_keep_aspect_mode(KeepAspect p_aspect) {
-
keep_aspect = p_aspect;
VisualServer::get_singleton()->camera_set_use_vertical_aspect(camera, p_aspect == KEEP_WIDTH);
-
+ _update_camera_mode();
_change_notify();
}
@@ -511,6 +424,7 @@ void Camera::set_doppler_tracking(DopplerTracking p_tracking) {
velocity_tracker->set_track_physics_step(doppler_tracking == DOPPLER_TRACKING_PHYSICS_STEP);
velocity_tracker->reset(get_global_transform().origin);
}
+ _update_camera_mode();
}
Camera::DopplerTracking Camera::get_doppler_tracking() const {
@@ -528,14 +442,20 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_perspective", "fov", "z_near", "z_far"), &Camera::set_perspective);
ClassDB::bind_method(D_METHOD("set_orthogonal", "size", "z_near", "z_far"), &Camera::set_orthogonal);
ClassDB::bind_method(D_METHOD("make_current"), &Camera::make_current);
- ClassDB::bind_method(D_METHOD("clear_current"), &Camera::clear_current);
+ ClassDB::bind_method(D_METHOD("clear_current", "enable_next"), &Camera::clear_current, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("set_current"), &Camera::set_current);
ClassDB::bind_method(D_METHOD("is_current"), &Camera::is_current);
ClassDB::bind_method(D_METHOD("get_camera_transform"), &Camera::get_camera_transform);
ClassDB::bind_method(D_METHOD("get_fov"), &Camera::get_fov);
ClassDB::bind_method(D_METHOD("get_size"), &Camera::get_size);
ClassDB::bind_method(D_METHOD("get_zfar"), &Camera::get_zfar);
ClassDB::bind_method(D_METHOD("get_znear"), &Camera::get_znear);
+ ClassDB::bind_method(D_METHOD("set_fov"), &Camera::set_fov);
+ ClassDB::bind_method(D_METHOD("set_size"), &Camera::set_size);
+ ClassDB::bind_method(D_METHOD("set_zfar"), &Camera::set_zfar);
+ ClassDB::bind_method(D_METHOD("set_znear"), &Camera::set_znear);
ClassDB::bind_method(D_METHOD("get_projection"), &Camera::get_projection);
+ ClassDB::bind_method(D_METHOD("set_projection"), &Camera::set_projection);
ClassDB::bind_method(D_METHOD("set_h_offset", "ofs"), &Camera::set_h_offset);
ClassDB::bind_method(D_METHOD("get_h_offset"), &Camera::get_h_offset);
ClassDB::bind_method(D_METHOD("set_v_offset", "ofs"), &Camera::set_v_offset);
@@ -550,6 +470,19 @@ void Camera::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_doppler_tracking"), &Camera::get_doppler_tracking);
//ClassDB::bind_method(D_METHOD("_camera_make_current"),&Camera::_camera_make_current );
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "keep_aspect", PROPERTY_HINT_ENUM, "Keep Width,Keep Height"), "set_keep_aspect_mode", "get_keep_aspect_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cull_mask", PROPERTY_HINT_LAYERS_3D_RENDER), "set_cull_mask", "get_cull_mask");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "doppler_tracking", PROPERTY_HINT_ENUM, "Disabled,Idle,Physics"), "set_doppler_tracking", "get_doppler_tracking");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "projection", PROPERTY_HINT_ENUM, "Perspective,Orthogonal"), "set_projection", "get_projection");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "current"), "set_current", "is_current");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "fov", PROPERTY_HINT_RANGE, "1,179,0.1"), "set_fov", "get_fov");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "size", PROPERTY_HINT_RANGE, "0.1,16384,0.01"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "near", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_znear", "get_znear");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "far", PROPERTY_HINT_EXP_RANGE, "0.1,8192,0.1,or_greater"), "set_zfar", "get_zfar");
+
BIND_ENUM_CONSTANT(PROJECTION_PERSPECTIVE);
BIND_ENUM_CONSTANT(PROJECTION_ORTHOGONAL);
@@ -586,10 +519,30 @@ Camera::Projection Camera::get_projection() const {
return mode;
}
-void Camera::set_cull_mask(uint32_t p_layers) {
+void Camera::set_fov(float p_fov) {
+ fov = p_fov;
+ _update_camera_mode();
+}
+
+void Camera::set_size(float p_size) {
+ size = p_size;
+ _update_camera_mode();
+}
+
+void Camera::set_znear(float p_znear) {
+ near = p_znear;
+ _update_camera_mode();
+}
+void Camera::set_zfar(float p_zfar) {
+ far = p_zfar;
+ _update_camera_mode();
+}
+
+void Camera::set_cull_mask(uint32_t p_layers) {
layers = p_layers;
VisualServer::get_singleton()->camera_set_cull_mask(camera, layers);
+ _update_camera_mode();
}
uint32_t Camera::get_cull_mask() const {
diff --git a/scene/3d/camera.h b/scene/3d/camera.h
index 73c6844c1a..1b506e0c4f 100644
--- a/scene/3d/camera.h
+++ b/scene/3d/camera.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CAMERA_H
#define CAMERA_H
@@ -95,10 +96,8 @@ protected:
virtual void _request_camera_update();
void _update_camera_mode();
- 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;
void _notification(int p_what);
+ virtual void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
@@ -111,9 +110,11 @@ public:
void set_perspective(float p_fovy_degrees, float p_z_near, float p_z_far);
void set_orthogonal(float p_size, float p_z_near, float p_z_far);
+ void set_projection(Camera::Projection p_mode);
void make_current();
- void clear_current();
+ void clear_current(bool p_enable_next = true);
+ void set_current(bool p_current);
bool is_current() const;
RID get_camera() const;
@@ -124,11 +125,16 @@ public:
float get_znear() const;
Projection get_projection() const;
+ void set_fov(float p_fov);
+ void set_size(float p_size);
+ void set_zfar(float p_zfar);
+ void set_znear(float p_znear);
+
virtual Transform get_camera_transform() const;
- Vector3 project_ray_normal(const Point2 &p_pos) const;
+ virtual Vector3 project_ray_normal(const Point2 &p_pos) const;
virtual Vector3 project_ray_origin(const Point2 &p_pos) const;
- Vector3 project_local_ray_normal(const Point2 &p_pos) const;
+ virtual Vector3 project_local_ray_normal(const Point2 &p_pos) const;
virtual Point2 unproject_position(const Vector3 &p_pos) const;
bool is_position_behind(const Vector3 &p_pos) const;
virtual Vector3 project_position(const Point2 &p_point) const;
diff --git a/scene/3d/collision_object.cpp b/scene/3d/collision_object.cpp
index 7b4770e435..1d5d1b2afe 100644
--- a/scene/3d/collision_object.cpp
+++ b/scene/3d/collision_object.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "collision_object.h"
#include "scene/scene_string_names.h"
@@ -364,6 +365,20 @@ bool CollisionObject::get_capture_input_on_drag() const {
return capture_input_on_drag;
}
+String CollisionObject::get_configuration_warning() const {
+
+ String warning = Spatial::get_configuration_warning();
+
+ if (shapes.empty()) {
+ if (warning == String()) {
+ warning += "\n";
+ }
+ warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape or CollisionPolygon as a child to define its shape.");
+ }
+
+ return warning;
+}
+
CollisionObject::CollisionObject() {
capture_input_on_drag = false;
diff --git a/scene/3d/collision_object.h b/scene/3d/collision_object.h
index ac35de697c..f31d65e411 100644
--- a/scene/3d/collision_object.h
+++ b/scene/3d/collision_object.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLLISION_OBJECT_H
#define COLLISION_OBJECT_H
@@ -108,6 +109,8 @@ public:
_FORCE_INLINE_ RID get_rid() const { return rid; }
+ virtual String get_configuration_warning() const;
+
CollisionObject();
~CollisionObject();
};
diff --git a/scene/3d/collision_polygon.cpp b/scene/3d/collision_polygon.cpp
index a6d812efec..379dd21c39 100644
--- a/scene/3d/collision_polygon.cpp
+++ b/scene/3d/collision_polygon.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "collision_polygon.h"
#include "collision_object.h"
@@ -72,6 +73,14 @@ void CollisionPolygon::_build_polygon() {
}
}
+void CollisionPolygon::_update_in_shape_owner(bool p_xform_only) {
+
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ if (p_xform_only)
+ return;
+ parent->shape_owner_set_disabled(owner_id, disabled);
+}
+
void CollisionPolygon::_notification(int p_what) {
switch (p_what) {
@@ -81,14 +90,20 @@ void CollisionPolygon::_notification(int p_what) {
if (parent) {
owner_id = parent->create_shape_owner(this);
_build_polygon();
- parent->shape_owner_set_transform(owner_id, get_transform());
- parent->shape_owner_set_disabled(owner_id, disabled);
+ _update_in_shape_owner();
+ }
+ } break;
+ case NOTIFICATION_ENTER_TREE: {
+
+ if (parent) {
+ _update_in_shape_owner();
}
+
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
- parent->shape_owner_set_transform(owner_id, get_transform());
+ _update_in_shape_owner(true);
}
} break;
@@ -158,6 +173,9 @@ String CollisionPolygon::get_configuration_warning() const {
return String();
}
+bool CollisionPolygon::_is_editable_3d_polygon() const {
+ return true;
+}
void CollisionPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_depth", "depth"), &CollisionPolygon::set_depth);
@@ -169,6 +187,8 @@ void CollisionPolygon::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disabled", "disabled"), &CollisionPolygon::set_disabled);
ClassDB::bind_method(D_METHOD("is_disabled"), &CollisionPolygon::is_disabled);
+ ClassDB::bind_method(D_METHOD("_is_editable_3d_polygon"), &CollisionPolygon::_is_editable_3d_polygon);
+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "depth"), "set_depth", "get_depth");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR2_ARRAY, "polygon"), "set_polygon", "get_polygon");
diff --git a/scene/3d/collision_polygon.h b/scene/3d/collision_polygon.h
index 14d8c3aba6..f1f137c9c5 100644
--- a/scene/3d/collision_polygon.h
+++ b/scene/3d/collision_polygon.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLLISION_POLYGON_H
#define COLLISION_POLYGON_H
@@ -50,6 +51,10 @@ protected:
void _build_polygon();
+ void _update_in_shape_owner(bool p_xform_only = false);
+
+ bool _is_editable_3d_polygon() const;
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/collision_shape.cpp b/scene/3d/collision_shape.cpp
index f49d89122d..943f4158f7 100644
--- a/scene/3d/collision_shape.cpp
+++ b/scene/3d/collision_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "collision_shape.h"
#include "scene/resources/box_shape.h"
#include "scene/resources/capsule_shape.h"
@@ -63,6 +64,14 @@ void CollisionShape::make_convex_from_brothers() {
}
}
+void CollisionShape::_update_in_shape_owner(bool p_xform_only) {
+
+ parent->shape_owner_set_transform(owner_id, get_transform());
+ if (p_xform_only)
+ return;
+ parent->shape_owner_set_disabled(owner_id, disabled);
+}
+
void CollisionShape::_notification(int p_what) {
switch (p_what) {
@@ -74,19 +83,20 @@ void CollisionShape::_notification(int p_what) {
if (shape.is_valid()) {
parent->shape_owner_add_shape(owner_id, shape);
}
- parent->shape_owner_set_transform(owner_id, get_transform());
- parent->shape_owner_set_disabled(owner_id, disabled);
+ _update_in_shape_owner();
}
} break;
case NOTIFICATION_ENTER_TREE: {
+ if (parent) {
+ _update_in_shape_owner();
+ }
if (get_tree()->is_debugging_collisions_hint()) {
_create_debug_shape();
}
-
} break;
case NOTIFICATION_LOCAL_TRANSFORM_CHANGED: {
if (parent) {
- parent->shape_owner_set_transform(owner_id, get_transform());
+ _update_in_shape_owner(true);
}
} break;
case NOTIFICATION_UNPARENTED: {
diff --git a/scene/3d/collision_shape.h b/scene/3d/collision_shape.h
index 94621177cb..c9c91a5824 100644
--- a/scene/3d/collision_shape.h
+++ b/scene/3d/collision_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLLISION_SHAPE_H
#define COLLISION_SHAPE_H
@@ -50,6 +51,8 @@ class CollisionShape : public Spatial {
void _create_debug_shape();
+ void _update_in_shape_owner(bool p_xform_only = false);
+
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/gi_probe.cpp b/scene/3d/gi_probe.cpp
index 9c811a74bf..4ad2eb60ee 100644
--- a/scene/3d/gi_probe.cpp
+++ b/scene/3d/gi_probe.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "gi_probe.h"
#include "mesh_instance.h"
@@ -534,7 +535,7 @@ void GIProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "normal_bias", PROPERTY_HINT_RANGE, "0,4,0.001"), "set_normal_bias", "get_normal_bias");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interior"), "set_interior", "is_interior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "compress"), "set_compress", "is_compressed");
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData"), "set_probe_data", "get_probe_data");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "data", PROPERTY_HINT_RESOURCE_TYPE, "GIProbeData", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE), "set_probe_data", "get_probe_data");
BIND_ENUM_CONSTANT(SUBDIV_64);
BIND_ENUM_CONSTANT(SUBDIV_128);
diff --git a/scene/3d/gi_probe.h b/scene/3d/gi_probe.h
index 0858af0001..af4b646590 100644
--- a/scene/3d/gi_probe.h
+++ b/scene/3d/gi_probe.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef GIPROBE_H
#define GIPROBE_H
diff --git a/scene/3d/immediate_geometry.cpp b/scene/3d/immediate_geometry.cpp
index 092ed8f0b2..14a0b0505d 100644
--- a/scene/3d/immediate_geometry.cpp
+++ b/scene/3d/immediate_geometry.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "immediate_geometry.h"
void ImmediateGeometry::begin(Mesh::PrimitiveType p_primitive, const Ref<Texture> &p_texture) {
diff --git a/scene/3d/immediate_geometry.h b/scene/3d/immediate_geometry.h
index 1ff4e05e82..f7201b4bba 100644
--- a/scene/3d/immediate_geometry.h
+++ b/scene/3d/immediate_geometry.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef IMMEDIATE_GEOMETRY_H
#define IMMEDIATE_GEOMETRY_H
diff --git a/scene/3d/interpolated_camera.cpp b/scene/3d/interpolated_camera.cpp
index 3ff8317732..ffa283f634 100644
--- a/scene/3d/interpolated_camera.cpp
+++ b/scene/3d/interpolated_camera.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "interpolated_camera.h"
#include "engine.h"
@@ -37,10 +38,10 @@ void InterpolatedCamera::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && enabled)
- set_physics_process(false);
+ set_process_internal(false);
} break;
- case NOTIFICATION_PROCESS: {
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (!enabled)
break;
@@ -110,9 +111,9 @@ void InterpolatedCamera::set_interpolation_enabled(bool p_enable) {
if (p_enable) {
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
return;
- set_process(true);
+ set_process_internal(true);
} else
- set_process(false);
+ set_process_internal(false);
}
bool InterpolatedCamera::is_interpolation_enabled() const {
diff --git a/scene/3d/interpolated_camera.h b/scene/3d/interpolated_camera.h
index 26e7278c99..b025112295 100644
--- a/scene/3d/interpolated_camera.h
+++ b/scene/3d/interpolated_camera.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef INTERPOLATED_CAMERA_H
#define INTERPOLATED_CAMERA_H
diff --git a/scene/3d/light.cpp b/scene/3d/light.cpp
index 6eb2028d8e..7c42638107 100644
--- a/scene/3d/light.cpp
+++ b/scene/3d/light.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "light.h"
#include "engine.h"
@@ -374,7 +375,7 @@ void DirectionalLight::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_normal_bias", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_param", "get_param", PARAM_SHADOW_NORMAL_BIAS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_bias_split_scale", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SHADOW_BIAS_SPLIT_SCALE);
ADD_PROPERTY(PropertyInfo(Variant::INT, "directional_shadow_depth_range", PROPERTY_HINT_ENUM, "Stable,Optimized"), "set_shadow_depth_range", "get_shadow_depth_range");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "directional_shadow_max_distance", PROPERTY_HINT_EXP_RANGE, "0,8192,0.1,or_greater"), "set_param", "get_param", PARAM_SHADOW_MAX_DISTANCE);
BIND_ENUM_CONSTANT(SHADOW_ORTHOGONAL);
BIND_ENUM_CONSTANT(SHADOW_PARALLEL_2_SPLITS);
@@ -427,8 +428,8 @@ void OmniLight::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shadow_detail"), &OmniLight::get_shadow_detail);
ADD_GROUP("Omni", "omni_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "omni_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_mode", PROPERTY_HINT_ENUM, "Dual Paraboloid,Cube"), "set_shadow_mode", "get_shadow_mode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "omni_shadow_detail", PROPERTY_HINT_ENUM, "Vertical,Horizontal"), "set_shadow_detail", "get_shadow_detail");
@@ -449,8 +450,8 @@ OmniLight::OmniLight() :
void SpotLight::_bind_methods() {
ADD_GROUP("Spot", "spot_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_RANGE, "0,65536,0.1"), "set_param", "get_param", PARAM_RANGE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_range", PROPERTY_HINT_EXP_RANGE, "0,4096,0.1,or_greater"), "set_param", "get_param", PARAM_RANGE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_ATTENUATION);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle", PROPERTY_HINT_RANGE, "0,180,0.1"), "set_param", "get_param", PARAM_SPOT_ANGLE);
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "spot_angle_attenuation", PROPERTY_HINT_EXP_EASING, "attenuation"), "set_param", "get_param", PARAM_SPOT_ATTENUATION);
}
diff --git a/scene/3d/light.h b/scene/3d/light.h
index 7ba25731d9..b35b397ced 100644
--- a/scene/3d/light.h
+++ b/scene/3d/light.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LIGHT_H
#define LIGHT_H
diff --git a/scene/3d/listener.cpp b/scene/3d/listener.cpp
index 51cf9fb89b..439c1f8c45 100644
--- a/scene/3d/listener.cpp
+++ b/scene/3d/listener.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "listener.h"
#include "scene/resources/mesh.h"
diff --git a/scene/3d/listener.h b/scene/3d/listener.h
index 2c800443b4..8047971ebd 100644
--- a/scene/3d/listener.h
+++ b/scene/3d/listener.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LISTENER_H
#define LISTENER_H
diff --git a/scene/3d/mesh_instance.cpp b/scene/3d/mesh_instance.cpp
index 1e52ccc6e0..80bae911d4 100644
--- a/scene/3d/mesh_instance.cpp
+++ b/scene/3d/mesh_instance.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "mesh_instance.h"
#include "collision_shape.h"
diff --git a/scene/3d/mesh_instance.h b/scene/3d/mesh_instance.h
index 970a10aaf3..5d359cd4d5 100644
--- a/scene/3d/mesh_instance.h
+++ b/scene/3d/mesh_instance.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MESH_INSTANCE_H
#define MESH_INSTANCE_H
diff --git a/scene/3d/multimesh_instance.cpp b/scene/3d/multimesh_instance.cpp
index ce7b97be7f..4cbd1df64a 100644
--- a/scene/3d/multimesh_instance.cpp
+++ b/scene/3d/multimesh_instance.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "multimesh_instance.h"
void MultiMeshInstance::_bind_methods() {
diff --git a/scene/3d/multimesh_instance.h b/scene/3d/multimesh_instance.h
index 9b2b1ff9a7..1cd077a0a5 100644
--- a/scene/3d/multimesh_instance.h
+++ b/scene/3d/multimesh_instance.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MULTIMESH_INSTANCE_H
#define MULTIMESH_INSTANCE_H
diff --git a/scene/3d/navigation.cpp b/scene/3d/navigation.cpp
index b6507aedb3..77bf703706 100644
--- a/scene/3d/navigation.cpp
+++ b/scene/3d/navigation.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "navigation.h"
void Navigation::_navmesh_link(int p_id) {
@@ -34,6 +35,7 @@ void Navigation::_navmesh_link(int p_id) {
ERR_FAIL_COND(!navmesh_map.has(p_id));
NavMesh &nm = navmesh_map[p_id];
ERR_FAIL_COND(nm.linked);
+ ERR_FAIL_COND(nm.navmesh.is_null());
PoolVector<Vector3> vertices = nm.navmesh->get_vertices();
int len = vertices.size();
@@ -202,7 +204,7 @@ void Navigation::_navmesh_unlink(int p_id) {
nm.linked = false;
}
-int Navigation::navmesh_create(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) {
+int Navigation::navmesh_add(const Ref<NavigationMesh> &p_mesh, const Transform &p_xform, Object *p_owner) {
int id = last_id++;
NavMesh nm;
@@ -686,7 +688,7 @@ Vector3 Navigation::get_up_vector() const {
void Navigation::_bind_methods() {
- ClassDB::bind_method(D_METHOD("navmesh_create", "mesh", "xform", "owner"), &Navigation::navmesh_create, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("navmesh_add", "mesh", "xform", "owner"), &Navigation::navmesh_add, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("navmesh_set_transform", "id", "xform"), &Navigation::navmesh_set_transform);
ClassDB::bind_method(D_METHOD("navmesh_remove", "id"), &Navigation::navmesh_remove);
diff --git a/scene/3d/navigation.h b/scene/3d/navigation.h
index d9a38f7b00..5a501039c8 100644
--- a/scene/3d/navigation.h
+++ b/scene/3d/navigation.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NAVIGATION_H
#define NAVIGATION_H
@@ -166,7 +167,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, Object *p_owner = NULL);
+ int navmesh_add(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 40750cdfe8..073e56fdb4 100644
--- a/scene/3d/navigation_mesh.cpp
+++ b/scene/3d/navigation_mesh.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "navigation_mesh.h"
#include "mesh_instance.h"
#include "navigation.h"
@@ -404,8 +405,8 @@ void NavigationMesh::_bind_methods() {
BIND_CONSTANT(SAMPLE_PARTITION_MONOTONE);
BIND_CONSTANT(SAMPLE_PARTITION_LAYERS);
- ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_vertices", "get_vertices");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_polygons", "_get_polygons");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "vertices", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_vertices", "get_vertices");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "polygons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_polygons", "_get_polygons");
ADD_PROPERTY(PropertyInfo(Variant::INT, "sample_partition_type/sample_partition_type", PROPERTY_HINT_ENUM, "Watershed,Monotone,Layers"), "set_sample_partition_type", "get_sample_partition_type");
@@ -471,7 +472,7 @@ void NavigationMeshInstance::set_enabled(bool p_enabled) {
if (navmesh.is_valid()) {
- nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this);
+ nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
}
}
@@ -508,7 +509,7 @@ void NavigationMeshInstance::_notification(int p_what) {
if (enabled && navmesh.is_valid()) {
- nav_id = navigation->navmesh_create(navmesh, get_relative_transform(navigation), this);
+ nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
break;
}
@@ -568,7 +569,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), this);
+ nav_id = navigation->navmesh_add(navmesh, get_relative_transform(navigation), this);
}
if (debug_view && navmesh.is_valid()) {
diff --git a/scene/3d/navigation_mesh.h b/scene/3d/navigation_mesh.h
index dd5ed79500..753ad76edc 100644
--- a/scene/3d/navigation_mesh.h
+++ b/scene/3d/navigation_mesh.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NAVIGATION_MESH_H
#define NAVIGATION_MESH_H
diff --git a/scene/3d/particles.cpp b/scene/3d/particles.cpp
index 821f1a5a78..7b5eb8ebc3 100644
--- a/scene/3d/particles.cpp
+++ b/scene/3d/particles.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "particles.h"
#include "scene/resources/surface_tool.h"
#include "servers/visual_server.h"
@@ -42,8 +43,7 @@ PoolVector<Face3> Particles::get_faces(uint32_t p_usage_flags) const {
void Particles::set_emitting(bool p_emitting) {
- emitting = p_emitting;
- VS::get_singleton()->particles_set_emitting(particles, emitting);
+ VS::get_singleton()->particles_set_emitting(particles, p_emitting);
}
void Particles::set_amount(int p_amount) {
@@ -63,7 +63,7 @@ void Particles::set_one_shot(bool p_one_shot) {
one_shot = p_one_shot;
VS::get_singleton()->particles_set_one_shot(particles, one_shot);
- if (!one_shot && emitting)
+ if (!one_shot && is_emitting())
VisualServer::get_singleton()->particles_restart(particles);
}
@@ -113,7 +113,7 @@ void Particles::set_speed_scale(float p_scale) {
bool Particles::is_emitting() const {
- return emitting;
+ return VS::get_singleton()->particles_get_emitting(particles);
}
int Particles::get_amount() const {
@@ -324,11 +324,11 @@ void Particles::_bind_methods() {
ClassDB::bind_method(D_METHOD("capture_aabb"), &Particles::capture_aabb);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,100000,1"), "set_amount", "get_amount");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_EXP_RANGE, "1,1000000,1"), "set_amount", "get_amount");
ADD_GROUP("Time", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lifetime", PROPERTY_HINT_EXP_RANGE, "0.01,600.0,0.01"), "set_lifetime", "get_lifetime");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "get_one_shot");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "preprocess", PROPERTY_HINT_EXP_RANGE, "0.00,600.0,0.01"), "set_pre_process_time", "get_pre_process_time");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "speed_scale", PROPERTY_HINT_RANGE, "0.01,64,0.01"), "set_speed_scale", "get_speed_scale");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "explosiveness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_explosiveness_ratio", "get_explosiveness_ratio");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "randomness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_randomness_ratio", "get_randomness_ratio");
@@ -598,6 +598,11 @@ void ParticlesMaterial::_update_shader() {
code += "}\n";
code += "\n";
+ code += "float rand_from_seed_m1_p1(inout uint seed) {\n";
+ code += " return rand_from_seed(seed)*2.0-1.0;\n";
+ code += "}\n";
+ code += "\n";
+
//improve seed quality
code += "uint hash(uint x) {\n";
code += " x = ((x >> uint(16)) ^ x) * uint(73244475);\n";
@@ -614,6 +619,8 @@ void ParticlesMaterial::_update_shader() {
code += " float scale_rand = rand_from_seed(alt_seed);\n";
code += " float hue_rot_rand = rand_from_seed(alt_seed);\n";
code += " float anim_offset_rand = rand_from_seed(alt_seed);\n";
+ code += " float pi = 3.14159;\n";
+ code += " float degree_to_rad = pi / 180.0;\n";
code += "\n";
if (emission_shape >= EMISSION_SHAPE_POINTS) {
@@ -638,23 +645,28 @@ void ParticlesMaterial::_update_shader() {
else
code += " float tex_anim_offset = 0.0;\n";
+ code += " float spread_rad = spread*degree_to_rad;\n";
+
if (flags[FLAG_DISABLE_Z]) {
- code += " float angle1 = (rand_from_seed(alt_seed)*2.0-1.0)*spread/180.0*3.1416;\n";
- code += " vec3 rot = vec3( cos(angle1), sin(angle1),0.0 );\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n";
+ code += " vec3 rot = vec3( cos(angle1_rad), sin(angle1_rad),0.0 );\n";
code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
} else {
//initiate velocity spread in 3D
- code += " float angle1 = rand_from_seed(alt_seed)*spread*3.1416;\n";
- code += " float angle2 = rand_from_seed(alt_seed)*20.0*3.1416; // make it more random like\n";
- code += " vec3 rot_xz = vec3( sin(angle1), 0.0, cos(angle1) );\n";
- code += " vec3 rot = vec3( cos(angle2)*rot_xz.x,sin(angle2)*rot_xz.x, rot_xz.z);\n";
- code += " VELOCITY = rot*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
+ code += " float angle1_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad;\n";
+ code += " float angle2_rad = rand_from_seed_m1_p1(alt_seed)*spread_rad*(1.0-flatness);\n";
+ code += " vec3 direction_xz = vec3( sin(angle1_rad), 0, cos(angle1_rad));\n";
+ code += " vec3 direction_yz = vec3( 0, sin(angle2_rad), cos(angle2_rad));\n";
+ code += " direction_yz.z = direction_yz.z / sqrt(direction_yz.z); //better uniform distribution\n";
+ code += " vec3 direction = vec3(direction_xz.x * direction_yz.z, direction_yz.y, direction_xz.z * direction_yz.z);\n";
+ code += " direction = normalize(direction);\n";
+ code += " VELOCITY = direction*initial_linear_velocity*mix(1.0, rand_from_seed(alt_seed), initial_linear_velocity_random);\n";
}
code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
- code += " CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle
+ code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle
code += " CUSTOM.y = 0.0;\n"; //phase
code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random);\n"; //animation offset (0-1)
switch (emission_shape) {
@@ -777,7 +789,7 @@ void ParticlesMaterial::_update_shader() {
code += " float orbit_amount = (orbit_velocity+tex_orbit_velocity)*mix(1.0,rand_from_seed(alt_seed),orbit_velocity_random);\n";
code += " if (orbit_amount!=0.0) {\n";
- code += " float ang = orbit_amount * DELTA * 3.1416 * 2.0;\n";
+ code += " float ang = orbit_amount * DELTA * pi * 2.0;\n";
code += " mat2 rot = mat2(vec2(cos(ang),-sin(ang)),vec2(sin(ang),cos(ang)));\n";
code += " TRANSFORM[3].xy-=diff.xy;\n";
code += " TRANSFORM[3].xy+=rot * diff.xy;\n";
@@ -800,7 +812,7 @@ void ParticlesMaterial::_update_shader() {
code += " }\n";
code += " float base_angle = (initial_angle+tex_angle)*mix(1.0,angle_rand,initial_angle_random);\n";
code += " base_angle += CUSTOM.y*LIFETIME*(angular_velocity+tex_angular_velocity)*mix(1.0,rand_from_seed(alt_seed)*2.0-1.0,angular_velocity_random);\n";
- code += " CUSTOM.x = base_angle*3.1416/180.0;\n"; //angle
+ code += " CUSTOM.x = base_angle*degree_to_rad;\n"; //angle
code += " CUSTOM.z = (anim_offset+tex_anim_offset)*mix(1.0,anim_offset_rand,anim_offset_random)+CUSTOM.y*(anim_speed+tex_anim_speed)*mix(1.0,rand_from_seed(alt_seed),anim_speed_random);\n"; //angle
if (flags[FLAG_ANIM_LOOP]) {
code += " CUSTOM.z = mod(CUSTOM.z,1.0);\n"; //loop
@@ -821,7 +833,7 @@ void ParticlesMaterial::_update_shader() {
else
code += " float tex_hue_variation = 0.0;\n";
- code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*3.1416*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
+ code += " float hue_rot_angle = (hue_variation+tex_hue_variation)*pi*2.0*mix(1.0,hue_rot_rand*2.0-1.0,hue_variation_random);\n";
code += " float hue_rot_c = cos(hue_rot_angle);\n";
code += " float hue_rot_s = sin(hue_rot_angle);\n";
code += " mat4 hue_rot_mat = mat4( vec4(0.299, 0.587, 0.114, 0.0),\n";
@@ -837,9 +849,9 @@ void ParticlesMaterial::_update_shader() {
code += " vec4(1.250, -1.050, -0.203, 0.0),\n";
code += " vec4(0.000, 0.000, 0.000, 0.0)) * hue_rot_s;\n";
if (color_ramp.is_valid()) {
- code += " COLOR = textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0) * hue_rot_mat;\n";
+ code += " COLOR = hue_rot_mat * textureLod(color_ramp,vec2(CUSTOM.y,0.0),0.0);\n";
} else {
- code += " COLOR = color_value * hue_rot_mat;\n";
+ code += " COLOR = hue_rot_mat * color_value;\n";
}
if (emission_color_texture.is_valid() && emission_shape >= EMISSION_SHAPE_POINTS) {
code += " COLOR*= texelFetch(emission_texture_color,emission_tex_ofs,0);\n";
@@ -1016,8 +1028,6 @@ void ParticlesMaterial::set_param(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset, p_value);
} break;
- case PARAM_MAX: {
- };
}
}
float ParticlesMaterial::get_param(Parameter p_param) const {
@@ -1070,8 +1080,6 @@ void ParticlesMaterial::set_param_randomness(Parameter p_param, float p_value) {
case PARAM_ANIM_OFFSET: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_random, p_value);
} break;
- case PARAM_MAX: {
- };
}
}
float ParticlesMaterial::get_param_randomness(Parameter p_param) const {
@@ -1148,8 +1156,6 @@ void ParticlesMaterial::set_param_texture(Parameter p_param, const Ref<Texture>
case PARAM_ANIM_OFFSET: {
VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->anim_offset_texture, p_texture);
} break;
- case PARAM_MAX: {
- };
}
_queue_shader_change();
@@ -1221,28 +1227,19 @@ void ParticlesMaterial::set_emission_box_extents(Vector3 p_extents) {
void ParticlesMaterial::set_emission_point_texture(const Ref<Texture> &p_points) {
emission_point_texture = p_points;
- RID texture;
- if (p_points.is_valid())
- texture = p_points->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_points, p_points);
}
void ParticlesMaterial::set_emission_normal_texture(const Ref<Texture> &p_normals) {
emission_normal_texture = p_normals;
- RID texture;
- if (p_normals.is_valid())
- texture = p_normals->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_normal, p_normals);
}
void ParticlesMaterial::set_emission_color_texture(const Ref<Texture> &p_colors) {
emission_color_texture = p_colors;
- RID texture;
- if (p_colors.is_valid())
- texture = p_colors->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->emission_texture_color, p_colors);
_queue_shader_change();
}
@@ -1304,10 +1301,7 @@ void ParticlesMaterial::set_trail_size_modifier(const Ref<CurveTexture> &p_trail
curve->ensure_default_setup();
}
- RID texture;
- if (p_trail_size_modifier.is_valid())
- texture = p_trail_size_modifier->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_size_modifier, curve);
_queue_shader_change();
}
@@ -1319,10 +1313,7 @@ Ref<CurveTexture> ParticlesMaterial::get_trail_size_modifier() const {
void ParticlesMaterial::set_trail_color_modifier(const Ref<GradientTexture> &p_trail_color_modifier) {
trail_color_modifier = p_trail_color_modifier;
- RID texture;
- if (p_trail_color_modifier.is_valid())
- texture = p_trail_color_modifier->get_rid();
- VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, texture);
+ VisualServer::get_singleton()->material_set_param(_get_material(), shader_names->trail_color_modifier, p_trail_color_modifier);
_queue_shader_change();
}
@@ -1469,26 +1460,26 @@ void ParticlesMaterial::_bind_methods() {
ADD_GROUP("Gravity", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
ADD_GROUP("Initial Velocity", "initial_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "initial_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_INITIAL_LINEAR_VELOCITY);
ADD_GROUP("Angular Velocity", "angular_");
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity", PROPERTY_HINT_RANGE, "-360,360,0.01"), "set_param", "get_param", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angular_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGULAR_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angular_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGULAR_VELOCITY);
ADD_GROUP("Orbit Velocity", "orbit_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity", PROPERTY_HINT_RANGE, "-1000,1000,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "orbit_velocity_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ORBIT_VELOCITY);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "orbit_velocity_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ORBIT_VELOCITY);
ADD_GROUP("Linear Accel", "linear_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_LINEAR_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "linear_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_LINEAR_ACCEL);
ADD_GROUP("Radial Accel", "radial_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "radial_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_RADIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "radial_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_RADIAL_ACCEL);
ADD_GROUP("Tangential Accel", "tangential_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel", PROPERTY_HINT_RANGE, "-100,100,0.01,or_lesser,or_greater"), "set_param", "get_param", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "tangential_accel_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_TANGENTIAL_ACCEL);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "tangential_accel_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_TANGENTIAL_ACCEL);
ADD_GROUP("Damping", "");
@@ -1496,11 +1487,11 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "damping_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_DAMPING);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "damping_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_DAMPING);
ADD_GROUP("Angle", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1"), "set_param", "get_param", PARAM_ANGLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle", PROPERTY_HINT_RANGE, "-720,720,0.1,or_lesser,or_greater"), "set_param", "get_param", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "angle_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANGLE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "angle_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANGLE);
ADD_GROUP("Scale", "");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01"), "set_param", "get_param", PARAM_SCALE);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale", PROPERTY_HINT_RANGE, "0,1000,0.01,or_greater"), "set_param", "get_param", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "scale_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_SCALE);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "scale_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_SCALE);
ADD_GROUP("Color", "");
@@ -1512,7 +1503,7 @@ void ParticlesMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "hue_variation_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_HUE_VARIATION);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "hue_variation_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_HUE_VARIATION);
ADD_GROUP("Animation", "anim_");
- ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01"), "set_param", "get_param", PARAM_ANIM_SPEED);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed", PROPERTY_HINT_RANGE, "0,128,0.01,or_greater"), "set_param", "get_param", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_speed_random", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param_randomness", "get_param_randomness", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "anim_speed_curve", PROPERTY_HINT_RESOURCE_TYPE, "CurveTexture"), "set_param_texture", "get_param_texture", PARAM_ANIM_SPEED);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "anim_offset", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_ANIM_OFFSET);
@@ -1585,4 +1576,21 @@ ParticlesMaterial::ParticlesMaterial() :
}
ParticlesMaterial::~ParticlesMaterial() {
+
+ if (material_mutex)
+ material_mutex->lock();
+
+ if (shader_map.has(current_key)) {
+ shader_map[current_key].users--;
+ if (shader_map[current_key].users == 0) {
+ //deallocate shader, as it's no longer in use
+ VS::get_singleton()->free(shader_map[current_key].shader);
+ shader_map.erase(current_key);
+ }
+
+ VS::get_singleton()->material_set_shader(_get_material(), RID());
+ }
+
+ if (material_mutex)
+ material_mutex->unlock();
}
diff --git a/scene/3d/particles.h b/scene/3d/particles.h
index 5b8121e937..17e21c6cee 100644
--- a/scene/3d/particles.h
+++ b/scene/3d/particles.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VISUALINSTANCEPARTICLES_H
#define VISUALINSTANCEPARTICLES_H
@@ -57,7 +58,6 @@ public:
private:
RID particles;
- bool emitting;
bool one_shot;
int amount;
float lifetime;
diff --git a/scene/3d/path.cpp b/scene/3d/path.cpp
index 65f20210e1..154dcb4259 100644
--- a/scene/3d/path.cpp
+++ b/scene/3d/path.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* 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 "engine.h"
@@ -39,6 +40,9 @@ void Path::_curve_changed() {
if (is_inside_tree() && Engine::get_singleton()->is_editor_hint())
update_gizmo();
+ if (is_inside_tree()) {
+ emit_signal("curve_changed");
+ }
}
void Path::set_curve(const Ref<Curve3D> &p_curve) {
@@ -67,6 +71,8 @@ void Path::_bind_methods() {
ClassDB::bind_method(D_METHOD("_curve_changed"), &Path::_curve_changed);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve3D"), "set_curve", "get_curve");
+
+ ADD_SIGNAL(MethodInfo("curve_changed"));
}
Path::Path() {
@@ -189,61 +195,16 @@ 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
- return false;
-
- return true;
-}
+void PathFollow::_validate_property(PropertyInfo &property) const {
-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
- 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"));
+ if (property.name == "offset") {
+
+ float max = 10000;
+ if (path && path->get_curve().is_valid())
+ max = path->get_curve()->get_baked_length();
+
+ property.hint_string = "0," + rtos(max) + ",0.01";
+ }
}
void PathFollow::_bind_methods() {
@@ -269,6 +230,14 @@ void PathFollow::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_loop", "loop"), &PathFollow::set_loop);
ClassDB::bind_method(D_METHOD("has_loop"), &PathFollow::has_loop);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "offset", PROPERTY_HINT_EXP_RANGE, "0,10000,0.01,or_greater"), "set_offset", "get_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "unit_offset", PROPERTY_HINT_RANGE, "0,1,0.0001", PROPERTY_USAGE_EDITOR), "set_unit_offset", "get_unit_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "h_offset"), "set_h_offset", "get_h_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_offset"), "set_v_offset", "get_v_offset");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "rotation_mode", PROPERTY_HINT_ENUM, "None,Y,XY,XYZ"), "set_rotation_mode", "get_rotation_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "cubic_interp"), "set_cubic_interpolation", "get_cubic_interpolation");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+
BIND_ENUM_CONSTANT(ROTATION_NONE);
BIND_ENUM_CONSTANT(ROTATION_Y);
BIND_ENUM_CONSTANT(ROTATION_XY);
diff --git a/scene/3d/path.h b/scene/3d/path.h
index 52760e0c75..2ed686ac3c 100644
--- a/scene/3d/path.h
+++ b/scene/3d/path.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PATH_H
#define PATH_H
@@ -78,9 +79,7 @@ private:
void _update_transform();
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;
+ virtual void _validate_property(PropertyInfo &property) const;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/physics_body.cpp b/scene/3d/physics_body.cpp
index c5f817d317..5056fb2fe4 100644
--- a/scene/3d/physics_body.cpp
+++ b/scene/3d/physics_body.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,12 +27,17 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "physics_body.h"
#include "engine.h"
#include "method_bind_ext.gen.inc"
#include "scene/scene_string_names.h"
+#ifdef TOOLS_ENABLED
+#include "editor/plugins/spatial_editor_plugin.h"
+#endif
+
void PhysicsBody::_notification(int p_what) {
/*
@@ -257,6 +262,7 @@ void RigidBody::_body_enter_tree(ObjectID p_id) {
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
+ ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(E->get().in_tree);
@@ -280,6 +286,7 @@ void RigidBody::_body_exit_tree(ObjectID p_id) {
Object *obj = ObjectDB::get_instance(p_id);
Node *node = Object::cast_to<Node>(obj);
ERR_FAIL_COND(!node);
+ ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(p_id);
ERR_FAIL_COND(!E);
ERR_FAIL_COND(!E->get().in_tree);
@@ -305,6 +312,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,
Object *obj = ObjectDB::get_instance(objid);
Node *node = Object::cast_to<Node>(obj);
+ ERR_FAIL_COND(!contact_monitor);
Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.find(objid);
ERR_FAIL_COND(!body_in && !E);
@@ -317,7 +325,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,
E->get().in_tree = node && node->is_inside_tree();
if (node) {
node->connect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree, make_binds(objid));
- node->connect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
+ node->connect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree, make_binds(objid));
if (E->get().in_tree) {
emit_signal(SceneStringNames::get_singleton()->body_entered, node);
}
@@ -344,7 +352,7 @@ void RigidBody::_body_inout(int p_status, ObjectID p_instance, int p_body_shape,
if (node) {
node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
- node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
if (in_tree)
emit_signal(SceneStringNames::get_singleton()->body_exited, obj);
}
@@ -366,9 +374,7 @@ struct _RigidBodyInOut {
void RigidBody::_direct_state_changed(Object *p_state) {
-//eh.. fuck
#ifdef DEBUG_ENABLED
-
state = Object::cast_to<PhysicsDirectBodyState>(p_state);
#else
state = (PhysicsDirectBodyState *)p_state; //trust it
@@ -692,6 +698,10 @@ void RigidBody::apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse) {
PhysicsServer::get_singleton()->body_apply_impulse(get_rid(), p_pos, p_impulse);
}
+void RigidBody::apply_torque_impulse(const Vector3 &p_impulse) {
+ PhysicsServer::get_singleton()->body_apply_torque_impulse(get_rid(), p_impulse);
+}
+
void RigidBody::set_use_continuous_collision_detection(bool p_enable) {
ccd = p_enable;
@@ -718,6 +728,14 @@ void RigidBody::set_contact_monitor(bool p_enabled) {
for (Map<ObjectID, BodyState>::Element *E = contact_monitor->body_map.front(); E; E = E->next()) {
//clean up mess
+ Object *obj = ObjectDB::get_instance(E->key());
+ Node *node = Object::cast_to<Node>(obj);
+
+ if (node) {
+
+ node->disconnect(SceneStringNames::get_singleton()->tree_entered, this, SceneStringNames::get_singleton()->_body_enter_tree);
+ node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, SceneStringNames::get_singleton()->_body_exit_tree);
+ }
}
memdelete(contact_monitor);
@@ -767,11 +785,11 @@ String RigidBody::get_configuration_warning() const {
String warning = CollisionObject::get_configuration_warning();
- if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(0).length() - 1.0) > 0.05)) {
+ if ((get_mode() == MODE_RIGID || get_mode() == MODE_CHARACTER) && (ABS(t.basis.get_axis(0).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(1).length() - 1.0) > 0.05 || ABS(t.basis.get_axis(2).length() - 1.0) > 0.05)) {
if (warning != String()) {
warning += "\n";
}
- warning += TTR("Size changes to RigidBody (in character or rigid modes) will be overriden by the physics engine when running.\nChange the size in children collision shapes instead.");
+ warning += TTR("Size changes to RigidBody (in character or rigid modes) will be overridden by the physics engine when running.\nChange the size in children collision shapes instead.");
}
return warning;
@@ -823,6 +841,7 @@ void RigidBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_axis_velocity", "axis_velocity"), &RigidBody::set_axis_velocity);
ClassDB::bind_method(D_METHOD("apply_impulse", "position", "impulse"), &RigidBody::apply_impulse);
+ ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &RigidBody::apply_torque_impulse);
ClassDB::bind_method(D_METHOD("set_sleeping", "sleeping"), &RigidBody::set_sleeping);
ClassDB::bind_method(D_METHOD("is_sleeping"), &RigidBody::is_sleeping);
@@ -913,10 +932,10 @@ RigidBody::~RigidBody() {
//////////////////////////////////////////////////////
//////////////////////////
-Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion) {
+Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion, bool p_infinite_inertia) {
Collision col;
- if (move_and_collide(p_motion, col)) {
+ if (move_and_collide(p_motion, p_infinite_inertia, col)) {
if (motion_cache.is_null()) {
motion_cache.instance();
motion_cache->owner = this;
@@ -930,11 +949,11 @@ Ref<KinematicCollision> KinematicBody::_move(const Vector3 &p_motion) {
return Ref<KinematicCollision>();
}
-bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_collision) {
+bool KinematicBody::move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision) {
Transform gt = get_global_transform();
PhysicsServer::MotionResult result;
- bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, &result);
+ bool colliding = PhysicsServer::get_singleton()->body_test_motion(get_rid(), gt, p_motion, p_infinite_inertia, &result);
if (colliding) {
r_collision.collider_metadata = result.collider_metadata;
@@ -960,7 +979,7 @@ bool KinematicBody::move_and_collide(const Vector3 &p_motion, Collision &r_colli
return colliding;
}
-Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
+Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction, bool p_infinite_inertia, float p_slope_stop_min_velocity, int p_max_slides, float p_floor_max_angle) {
Vector3 lv = p_linear_velocity;
@@ -982,7 +1001,7 @@ Vector3 KinematicBody::move_and_slide(const Vector3 &p_linear_velocity, const Ve
Collision collision;
- bool collided = move_and_collide(motion, collision);
+ bool collided = move_and_collide(motion, p_infinite_inertia, collision);
if (collided) {
@@ -1055,11 +1074,11 @@ Vector3 KinematicBody::get_floor_velocity() const {
return floor_velocity;
}
-bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion) {
+bool KinematicBody::test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia) {
ERR_FAIL_COND_V(!is_inside_tree(), false);
- return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion);
+ return PhysicsServer::get_singleton()->body_test_motion(get_rid(), p_from, p_motion, p_infinite_inertia);
}
void KinematicBody::set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock) {
@@ -1108,10 +1127,10 @@ Ref<KinematicCollision> KinematicBody::_get_slide_collision(int p_bounce) {
void KinematicBody::_bind_methods() {
- ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec"), &KinematicBody::_move);
- ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
+ ClassDB::bind_method(D_METHOD("move_and_collide", "rel_vec", "infinite_inertia"), &KinematicBody::_move, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("move_and_slide", "linear_velocity", "floor_normal", "infinite_inertia", "slope_stop_min_velocity", "max_slides", "floor_max_angle"), &KinematicBody::move_and_slide, DEFVAL(Vector3(0, 0, 0)), DEFVAL(true), DEFVAL(0.05), DEFVAL(4), DEFVAL(Math::deg2rad((float)45)));
- ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec"), &KinematicBody::test_move);
+ ClassDB::bind_method(D_METHOD("test_move", "from", "rel_vec", "infinite_inertia"), &KinematicBody::test_move);
ClassDB::bind_method(D_METHOD("is_on_floor"), &KinematicBody::is_on_floor);
ClassDB::bind_method(D_METHOD("is_on_ceiling"), &KinematicBody::is_on_ceiling);
@@ -1251,3 +1270,1112 @@ KinematicCollision::KinematicCollision() {
collision.local_shape = 0;
owner = NULL;
}
+
+///////////////////////////////////////
+
+bool PhysicalBone::JointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ return false;
+}
+
+bool PhysicalBone::JointData::_get(const StringName &p_name, Variant &r_ret) const {
+ return false;
+}
+
+void PhysicalBone::JointData::_get_property_list(List<PropertyInfo> *p_list) const {
+}
+
+bool PhysicalBone::PinJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/bias" == p_name) {
+ bias = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_BIAS, bias);
+
+ } else if ("joint_constraints/damping" == p_name) {
+ damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_DAMPING, damping);
+
+ } else if ("joint_constraints/impulse_clamp" == p_name) {
+ impulse_clamp = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->pin_joint_set_param(j, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, impulse_clamp);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::PinJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/bias" == p_name) {
+ r_ret = bias;
+ } else if ("joint_constraints/damping" == p_name) {
+ r_ret = damping;
+ } else if ("joint_constraints/impulse_clamp" == p_name) {
+ r_ret = impulse_clamp;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::PinJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/damping", PROPERTY_HINT_RANGE, "0.01,8.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/impulse_clamp", PROPERTY_HINT_RANGE, "0.0,64.0,0.01"));
+}
+
+bool PhysicalBone::ConeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/swing_span" == p_name) {
+ swing_span = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, swing_span);
+
+ } else if ("joint_constraints/twist_span" == p_name) {
+ twist_span = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, twist_span);
+
+ } else if ("joint_constraints/bias" == p_name) {
+ bias = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_BIAS, bias);
+
+ } else if ("joint_constraints/softness" == p_name) {
+ softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, softness);
+
+ } else if ("joint_constraints/relaxation" == p_name) {
+ relaxation = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(j, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, relaxation);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::ConeJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/swing_span" == p_name) {
+ r_ret = Math::rad2deg(swing_span);
+ } else if ("joint_constraints/twist_span" == p_name) {
+ r_ret = Math::rad2deg(twist_span);
+ } else if ("joint_constraints/bias" == p_name) {
+ r_ret = bias;
+ } else if ("joint_constraints/softness" == p_name) {
+ r_ret = softness;
+ } else if ("joint_constraints/relaxation" == p_name) {
+ r_ret = relaxation;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::ConeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/swing_span", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/twist_span", PROPERTY_HINT_RANGE, "-40000,40000,0.1,or_lesser,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/bias", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/relaxation", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+}
+
+bool PhysicalBone::HingeJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/angular_limit_enabled" == p_name) {
+ angular_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_flag(j, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, angular_limit_enabled);
+
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, angular_limit_upper);
+
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, angular_limit_lower);
+
+ } else if ("joint_constraints/angular_limit_bias" == p_name) {
+ angular_limit_bias = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, angular_limit_bias);
+
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
+ angular_limit_relaxation = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->hinge_joint_set_param(j, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, angular_limit_relaxation);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::HingeJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/angular_limit_enabled" == p_name) {
+ r_ret = angular_limit_enabled;
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_upper);
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_lower);
+ } else if ("joint_constraints/angular_limit_bias" == p_name) {
+ r_ret = angular_limit_bias;
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ r_ret = angular_limit_softness;
+ } else if ("joint_constraints/angular_limit_relaxation" == p_name) {
+ r_ret = angular_limit_relaxation;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::HingeJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/angular_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_bias", PROPERTY_HINT_RANGE, "0.01,0.99,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_relaxation", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+}
+
+bool PhysicalBone::SliderJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ if ("joint_constraints/linear_limit_upper" == p_name) {
+ linear_limit_upper = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, linear_limit_upper);
+
+ } else if ("joint_constraints/linear_limit_lower" == p_name) {
+ linear_limit_lower = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, linear_limit_lower);
+
+ } else if ("joint_constraints/linear_limit_softness" == p_name) {
+ linear_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, linear_limit_softness);
+
+ } else if ("joint_constraints/linear_limit_restitution" == p_name) {
+ linear_limit_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, linear_limit_restitution);
+
+ } else if ("joint_constraints/linear_limit_damping" == p_name) {
+ linear_limit_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, linear_limit_restitution);
+
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, angular_limit_upper);
+
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, angular_limit_lower);
+
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_restitution" == p_name) {
+ angular_limit_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, angular_limit_softness);
+
+ } else if ("joint_constraints/angular_limit_damping" == p_name) {
+ angular_limit_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->slider_joint_set_param(j, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, angular_limit_damping);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::SliderJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ if ("joint_constraints/linear_limit_upper" == p_name) {
+ r_ret = linear_limit_upper;
+ } else if ("joint_constraints/linear_limit_lower" == p_name) {
+ r_ret = linear_limit_lower;
+ } else if ("joint_constraints/linear_limit_softness" == p_name) {
+ r_ret = linear_limit_softness;
+ } else if ("joint_constraints/linear_limit_restitution" == p_name) {
+ r_ret = linear_limit_restitution;
+ } else if ("joint_constraints/linear_limit_damping" == p_name) {
+ r_ret = linear_limit_damping;
+ } else if ("joint_constraints/angular_limit_upper" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_upper);
+ } else if ("joint_constraints/angular_limit_lower" == p_name) {
+ r_ret = Math::rad2deg(angular_limit_lower);
+ } else if ("joint_constraints/angular_limit_softness" == p_name) {
+ r_ret = angular_limit_softness;
+ } else if ("joint_constraints/angular_limit_restitution" == p_name) {
+ r_ret = angular_limit_restitution;
+ } else if ("joint_constraints/angular_limit_damping" == p_name) {
+ r_ret = angular_limit_damping;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::SliderJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ JointData::_get_property_list(p_list);
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_upper"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_lower"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/linear_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
+
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_restitution", PROPERTY_HINT_RANGE, "0.01,16.0,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/angular_limit_damping", PROPERTY_HINT_RANGE, "0,16.0,0.01"));
+}
+
+bool PhysicalBone::SixDOFJointData::_set(const StringName &p_name, const Variant &p_value, RID j) {
+ if (JointData::_set(p_name, p_value, j)) {
+ return true;
+ }
+
+ String path = p_name;
+
+ Vector3::Axis axis;
+ {
+ const String axis_s = path.get_slicec('/', 1);
+ if ("x" == axis_s) {
+ axis = Vector3::AXIS_X;
+ } else if ("y" == axis_s) {
+ axis = Vector3::AXIS_Y;
+ } else if ("z" == axis_s) {
+ axis = Vector3::AXIS_Z;
+ } else {
+ return false;
+ }
+ }
+
+ String var_name = path.get_slicec('/', 2);
+
+ if ("linear_limit_enabled" == var_name) {
+ axis_data[axis].linear_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, axis_data[axis].linear_limit_enabled);
+
+ } else if ("linear_limit_upper" == var_name) {
+ axis_data[axis].linear_limit_upper = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, axis_data[axis].linear_limit_upper);
+
+ } else if ("linear_limit_lower" == var_name) {
+ axis_data[axis].linear_limit_lower = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, axis_data[axis].linear_limit_lower);
+
+ } else if ("linear_limit_softness" == var_name) {
+ axis_data[axis].linear_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, axis_data[axis].linear_limit_softness);
+
+ } else if ("linear_restitution" == var_name) {
+ axis_data[axis].linear_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, axis_data[axis].linear_restitution);
+
+ } else if ("linear_damping" == var_name) {
+ axis_data[axis].linear_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, axis_data[axis].linear_damping);
+
+ } else if ("angular_limit_enabled" == var_name) {
+ axis_data[axis].angular_limit_enabled = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(j, axis, PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, axis_data[axis].angular_limit_enabled);
+
+ } else if ("angular_limit_upper" == var_name) {
+ axis_data[axis].angular_limit_upper = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, axis_data[axis].angular_limit_upper);
+
+ } else if ("angular_limit_lower" == var_name) {
+ axis_data[axis].angular_limit_lower = Math::deg2rad(real_t(p_value));
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, axis_data[axis].angular_limit_lower);
+
+ } else if ("angular_limit_softness" == var_name) {
+ axis_data[axis].angular_limit_softness = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, axis_data[axis].angular_limit_softness);
+
+ } else if ("angular_restitution" == var_name) {
+ axis_data[axis].angular_restitution = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, axis_data[axis].angular_restitution);
+
+ } else if ("angular_damping" == var_name) {
+ axis_data[axis].angular_damping = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, axis_data[axis].angular_damping);
+
+ } else if ("erp" == var_name) {
+ axis_data[axis].erp = p_value;
+ if (j.is_valid())
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(j, axis, PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, axis_data[axis].erp);
+
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+bool PhysicalBone::SixDOFJointData::_get(const StringName &p_name, Variant &r_ret) const {
+ if (JointData::_get(p_name, r_ret)) {
+ return true;
+ }
+
+ String path = p_name;
+
+ int axis;
+ {
+ const String axis_s = path.get_slicec('/', 1);
+ if ("x" == axis_s) {
+ axis = 0;
+ } else if ("y" == axis_s) {
+ axis = 1;
+ } else if ("z" == axis_s) {
+ axis = 2;
+ } else {
+ return false;
+ }
+ }
+
+ String var_name = path.get_slicec('/', 2);
+
+ if ("linear_limit_enabled" == var_name) {
+ r_ret = axis_data[axis].linear_limit_enabled;
+ } else if ("linear_limit_upper" == var_name) {
+ r_ret = axis_data[axis].linear_limit_upper;
+ } else if ("linear_limit_lower" == var_name) {
+ r_ret = axis_data[axis].linear_limit_lower;
+ } else if ("linear_limit_softness" == var_name) {
+ r_ret = axis_data[axis].linear_limit_softness;
+ } else if ("linear_restitution" == var_name) {
+ r_ret = axis_data[axis].linear_restitution;
+ } else if ("linear_damping" == var_name) {
+ r_ret = axis_data[axis].linear_damping;
+ } else if ("angular_limit_enabled" == var_name) {
+ r_ret = axis_data[axis].angular_limit_enabled;
+ } else if ("angular_limit_upper" == var_name) {
+ r_ret = Math::rad2deg(axis_data[axis].angular_limit_upper);
+ } else if ("angular_limit_lower" == var_name) {
+ r_ret = Math::rad2deg(axis_data[axis].angular_limit_lower);
+ } else if ("angular_limit_softness" == var_name) {
+ r_ret = axis_data[axis].angular_limit_softness;
+ } else if ("angular_restitution" == var_name) {
+ r_ret = axis_data[axis].angular_restitution;
+ } else if ("angular_damping" == var_name) {
+ r_ret = axis_data[axis].angular_damping;
+ } else if ("erp" == var_name) {
+ r_ret = axis_data[axis].erp;
+ } else {
+ return false;
+ }
+
+ return true;
+}
+
+void PhysicalBone::SixDOFJointData::_get_property_list(List<PropertyInfo> *p_list) const {
+ const StringName axis_names[] = { "x", "y", "z" };
+ for (int i = 0; i < 3; ++i) {
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/linear_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_upper"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_lower"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/linear_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "joint_constraints/" + axis_names[i] + "/angular_limit_enabled"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_upper", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_lower", PROPERTY_HINT_RANGE, "-180,180,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_limit_softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/angular_damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"));
+ p_list->push_back(PropertyInfo(Variant::REAL, "joint_constraints/" + axis_names[i] + "/erp"));
+ }
+}
+
+bool PhysicalBone::_set(const StringName &p_name, const Variant &p_value) {
+ if (p_name == "bone_name") {
+ set_bone_name(p_value);
+ return true;
+ }
+
+ if (joint_data) {
+ if (joint_data->_set(p_name, p_value)) {
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool PhysicalBone::_get(const StringName &p_name, Variant &r_ret) const {
+ if (p_name == "bone_name") {
+ r_ret = get_bone_name();
+ return true;
+ }
+
+ if (joint_data) {
+ return joint_data->_get(p_name, r_ret);
+ }
+
+ return false;
+}
+
+void PhysicalBone::_get_property_list(List<PropertyInfo> *p_list) const {
+
+ Skeleton *parent = find_skeleton_parent(get_parent());
+
+ if (parent) {
+
+ String names;
+ for (int i = 0; i < parent->get_bone_count(); i++) {
+ if (i > 0)
+ names += ",";
+ names += parent->get_bone_name(i);
+ }
+
+ p_list->push_back(PropertyInfo(Variant::STRING, "bone_name", PROPERTY_HINT_ENUM, names));
+ } else {
+
+ p_list->push_back(PropertyInfo(Variant::STRING, "bone_name"));
+ }
+
+ if (joint_data) {
+ joint_data->_get_property_list(p_list);
+ }
+}
+
+void PhysicalBone::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ parent_skeleton = find_skeleton_parent(get_parent());
+ update_bone_id();
+ reset_to_rest_position();
+ _reset_physics_simulation_state();
+ break;
+ case NOTIFICATION_EXIT_TREE:
+ if (parent_skeleton) {
+ if (-1 != bone_id) {
+ parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ }
+ }
+ parent_skeleton = NULL;
+ update_bone_id();
+ break;
+ case NOTIFICATION_TRANSFORM_CHANGED:
+ if (Engine::get_singleton()->is_editor_hint()) {
+
+ update_offset();
+ }
+ break;
+ }
+}
+
+void PhysicalBone::_direct_state_changed(Object *p_state) {
+
+ if (!simulate_physics) {
+ return;
+ }
+
+ /// Update bone transform
+
+ PhysicsDirectBodyState *state;
+
+#ifdef DEBUG_ENABLED
+ state = Object::cast_to<PhysicsDirectBodyState>(p_state);
+#else
+ state = (PhysicsDirectBodyState *)p_state; //trust it
+#endif
+
+ Transform global_transform(state->get_transform());
+
+ set_ignore_transform_notification(true);
+ set_global_transform(global_transform);
+ set_ignore_transform_notification(false);
+
+ // Update skeleton
+ if (parent_skeleton) {
+ if (-1 != bone_id) {
+ parent_skeleton->set_bone_global_pose(bone_id, parent_skeleton->get_global_transform().affine_inverse() * (global_transform * body_offset_inverse));
+ }
+ }
+}
+
+void PhysicalBone::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_direct_state_changed"), &PhysicalBone::_direct_state_changed);
+
+ ClassDB::bind_method(D_METHOD("set_joint_type", "joint_type"), &PhysicalBone::set_joint_type);
+ ClassDB::bind_method(D_METHOD("get_joint_type"), &PhysicalBone::get_joint_type);
+
+ ClassDB::bind_method(D_METHOD("set_joint_offset", "offset"), &PhysicalBone::set_joint_offset);
+ ClassDB::bind_method(D_METHOD("get_joint_offset"), &PhysicalBone::get_joint_offset);
+
+ ClassDB::bind_method(D_METHOD("set_body_offset", "offset"), &PhysicalBone::set_body_offset);
+ ClassDB::bind_method(D_METHOD("get_body_offset"), &PhysicalBone::get_body_offset);
+
+ ClassDB::bind_method(D_METHOD("is_static_body"), &PhysicalBone::is_static_body);
+
+ ClassDB::bind_method(D_METHOD("get_simulate_physics"), &PhysicalBone::get_simulate_physics);
+
+ ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBone::is_simulating_physics);
+
+ ClassDB::bind_method(D_METHOD("set_mass", "mass"), &PhysicalBone::set_mass);
+ ClassDB::bind_method(D_METHOD("get_mass"), &PhysicalBone::get_mass);
+
+ ClassDB::bind_method(D_METHOD("set_weight", "weight"), &PhysicalBone::set_weight);
+ ClassDB::bind_method(D_METHOD("get_weight"), &PhysicalBone::get_weight);
+
+ ClassDB::bind_method(D_METHOD("set_friction", "friction"), &PhysicalBone::set_friction);
+ ClassDB::bind_method(D_METHOD("get_friction"), &PhysicalBone::get_friction);
+
+ ClassDB::bind_method(D_METHOD("set_bounce", "bounce"), &PhysicalBone::set_bounce);
+ ClassDB::bind_method(D_METHOD("get_bounce"), &PhysicalBone::get_bounce);
+
+ ClassDB::bind_method(D_METHOD("set_gravity_scale", "gravity_scale"), &PhysicalBone::set_gravity_scale);
+ ClassDB::bind_method(D_METHOD("get_gravity_scale"), &PhysicalBone::get_gravity_scale);
+
+ ADD_GROUP("Joint", "joint_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "joint_type", PROPERTY_HINT_ENUM, "None,PinJoint,ConeJoint,HingeJoint,SliderJoint,6DOFJoint"), "set_joint_type", "get_joint_type");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "joint_offset"), "set_joint_offset", "get_joint_offset");
+
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM, "body_offset"), "set_body_offset", "get_body_offset");
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_mass", "get_mass");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "weight", PROPERTY_HINT_EXP_RANGE, "0.01,65535,0.01"), "set_weight", "get_weight");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_friction", "get_friction");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bounce", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_bounce", "get_bounce");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "gravity_scale", PROPERTY_HINT_RANGE, "-10,10,0.01"), "set_gravity_scale", "get_gravity_scale");
+
+ BIND_ENUM_CONSTANT(JOINT_TYPE_NONE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_PIN);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_CONE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_HINGE);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_SLIDER);
+ BIND_ENUM_CONSTANT(JOINT_TYPE_6DOF);
+}
+
+Skeleton *PhysicalBone::find_skeleton_parent(Node *p_parent) {
+ if (!p_parent) {
+ return NULL;
+ }
+ Skeleton *s = Object::cast_to<Skeleton>(p_parent);
+ return s ? s : find_skeleton_parent(p_parent->get_parent());
+}
+
+void PhysicalBone::_fix_joint_offset() {
+ // Clamp joint origin to bone origin
+ if (parent_skeleton) {
+ joint_offset.origin = body_offset.affine_inverse().origin;
+ }
+}
+
+void PhysicalBone::_reload_joint() {
+
+ if (joint.is_valid()) {
+ PhysicsServer::get_singleton()->free(joint);
+ joint = RID();
+ }
+
+ if (!parent_skeleton) {
+ return;
+ }
+
+ PhysicalBone *body_a = parent_skeleton->get_physical_bone_parent(bone_id);
+ if (!body_a) {
+ return;
+ }
+
+ Transform joint_transf = get_global_transform() * joint_offset;
+ Transform local_a = body_a->get_global_transform().affine_inverse() * joint_transf;
+ local_a.orthonormalize();
+
+ switch (get_joint_type()) {
+ case JOINT_TYPE_PIN: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_pin(body_a->get_rid(), local_a.origin, get_rid(), joint_offset.origin);
+ const PinJointData *pjd(static_cast<const PinJointData *>(joint_data));
+ PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_BIAS, pjd->bias);
+ PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_DAMPING, pjd->damping);
+ PhysicsServer::get_singleton()->pin_joint_set_param(joint, PhysicsServer::PIN_JOINT_IMPULSE_CLAMP, pjd->impulse_clamp);
+
+ } break;
+ case JOINT_TYPE_CONE: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_cone_twist(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const ConeJointData *cjd(static_cast<const ConeJointData *>(joint_data));
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SWING_SPAN, cjd->swing_span);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_TWIST_SPAN, cjd->twist_span);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_BIAS, cjd->bias);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_SOFTNESS, cjd->softness);
+ PhysicsServer::get_singleton()->cone_twist_joint_set_param(joint, PhysicsServer::CONE_TWIST_JOINT_RELAXATION, cjd->relaxation);
+
+ } break;
+ case JOINT_TYPE_HINGE: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_hinge(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const HingeJointData *hjd(static_cast<const HingeJointData *>(joint_data));
+ PhysicsServer::get_singleton()->hinge_joint_set_flag(joint, PhysicsServer::HINGE_JOINT_FLAG_USE_LIMIT, hjd->angular_limit_enabled);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_UPPER, hjd->angular_limit_upper);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_LOWER, hjd->angular_limit_lower);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_BIAS, hjd->angular_limit_bias);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_SOFTNESS, hjd->angular_limit_softness);
+ PhysicsServer::get_singleton()->hinge_joint_set_param(joint, PhysicsServer::HINGE_JOINT_LIMIT_RELAXATION, hjd->angular_limit_relaxation);
+
+ } break;
+ case JOINT_TYPE_SLIDER: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_slider(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const SliderJointData *sjd(static_cast<const SliderJointData *>(joint_data));
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_UPPER, sjd->linear_limit_upper);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_LOWER, sjd->linear_limit_lower);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_SOFTNESS, sjd->linear_limit_softness);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_RESTITUTION, sjd->linear_limit_restitution);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_LINEAR_LIMIT_DAMPING, sjd->linear_limit_restitution);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_UPPER, sjd->angular_limit_upper);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_LOWER, sjd->angular_limit_lower);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_SOFTNESS, sjd->angular_limit_softness);
+ PhysicsServer::get_singleton()->slider_joint_set_param(joint, PhysicsServer::SLIDER_JOINT_ANGULAR_LIMIT_DAMPING, sjd->angular_limit_damping);
+
+ } break;
+ case JOINT_TYPE_6DOF: {
+
+ joint = PhysicsServer::get_singleton()->joint_create_generic_6dof(body_a->get_rid(), local_a, get_rid(), joint_offset);
+ const SixDOFJointData *g6dofjd(static_cast<const SixDOFJointData *>(joint_data));
+ for (int axis = 0; axis < 3; ++axis) {
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT, g6dofjd->axis_data[axis].linear_limit_enabled);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_UPPER_LIMIT, g6dofjd->axis_data[axis].linear_limit_upper);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LOWER_LIMIT, g6dofjd->axis_data[axis].linear_limit_lower);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].linear_limit_softness);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION, g6dofjd->axis_data[axis].linear_restitution);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING, g6dofjd->axis_data[axis].linear_damping);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_flag(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT, g6dofjd->axis_data[axis].angular_limit_enabled);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT, g6dofjd->axis_data[axis].angular_limit_upper);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT, g6dofjd->axis_data[axis].angular_limit_lower);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS, g6dofjd->axis_data[axis].angular_limit_softness);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_RESTITUTION, g6dofjd->axis_data[axis].angular_restitution);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_DAMPING, g6dofjd->axis_data[axis].angular_damping);
+ PhysicsServer::get_singleton()->generic_6dof_joint_set_param(joint, static_cast<Vector3::Axis>(axis), PhysicsServer::G6DOF_JOINT_ANGULAR_ERP, g6dofjd->axis_data[axis].erp);
+ }
+
+ } break;
+ }
+}
+
+void PhysicalBone::_on_bone_parent_changed() {
+ _reload_joint();
+}
+
+void PhysicalBone::_set_gizmo_move_joint(bool p_move_joint) {
+#ifdef TOOLS_ENABLED
+ gizmo_move_joint = p_move_joint;
+ SpatialEditor::get_singleton()->update_transform_gizmo();
+#endif
+}
+
+#ifdef TOOLS_ENABLED
+Transform PhysicalBone::get_global_gizmo_transform() const {
+ return gizmo_move_joint ? get_global_transform() * joint_offset : get_global_transform();
+}
+
+Transform PhysicalBone::get_local_gizmo_transform() const {
+ return gizmo_move_joint ? get_transform() * joint_offset : get_transform();
+}
+#endif
+
+const PhysicalBone::JointData *PhysicalBone::get_joint_data() const {
+ return joint_data;
+}
+
+Skeleton *PhysicalBone::find_skeleton_parent() {
+ return find_skeleton_parent(this);
+}
+
+void PhysicalBone::set_joint_type(JointType p_joint_type) {
+
+ if (p_joint_type == get_joint_type())
+ return;
+
+ memdelete(joint_data);
+ joint_data = NULL;
+ switch (p_joint_type) {
+ case JOINT_TYPE_PIN:
+ joint_data = memnew(PinJointData);
+ break;
+ case JOINT_TYPE_CONE:
+ joint_data = memnew(ConeJointData);
+ break;
+ case JOINT_TYPE_HINGE:
+ joint_data = memnew(HingeJointData);
+ break;
+ case JOINT_TYPE_SLIDER:
+ joint_data = memnew(SliderJointData);
+ break;
+ case JOINT_TYPE_6DOF:
+ joint_data = memnew(SixDOFJointData);
+ break;
+ }
+
+ _reload_joint();
+
+#ifdef TOOLS_ENABLED
+ _change_notify();
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+PhysicalBone::JointType PhysicalBone::get_joint_type() const {
+ return joint_data ? joint_data->get_joint_type() : JOINT_TYPE_NONE;
+}
+
+void PhysicalBone::set_joint_offset(const Transform &p_offset) {
+ joint_offset = p_offset;
+
+ _fix_joint_offset();
+
+ set_ignore_transform_notification(true);
+ reset_to_rest_position();
+ set_ignore_transform_notification(false);
+
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+const Transform &PhysicalBone::get_body_offset() const {
+ return body_offset;
+}
+
+void PhysicalBone::set_body_offset(const Transform &p_offset) {
+ body_offset = p_offset;
+ body_offset_inverse = body_offset.affine_inverse();
+
+ _fix_joint_offset();
+
+ set_ignore_transform_notification(true);
+ reset_to_rest_position();
+ set_ignore_transform_notification(false);
+
+#ifdef TOOLS_ENABLED
+ if (get_gizmo().is_valid())
+ get_gizmo()->redraw();
+#endif
+}
+
+const Transform &PhysicalBone::get_joint_offset() const {
+ return joint_offset;
+}
+
+void PhysicalBone::set_static_body(bool p_static) {
+
+ static_body = p_static;
+
+ set_as_toplevel(!static_body);
+
+ _reset_physics_simulation_state();
+}
+
+bool PhysicalBone::is_static_body() {
+ return static_body;
+}
+
+void PhysicalBone::set_simulate_physics(bool p_simulate) {
+ if (simulate_physics == p_simulate) {
+ return;
+ }
+
+ simulate_physics = p_simulate;
+ _reset_physics_simulation_state();
+}
+
+bool PhysicalBone::get_simulate_physics() {
+ return simulate_physics;
+}
+
+bool PhysicalBone::is_simulating_physics() {
+ return _internal_simulate_physics && !_internal_static_body;
+}
+
+void PhysicalBone::set_bone_name(const String &p_name) {
+
+ bone_name = p_name;
+ bone_id = -1;
+
+ update_bone_id();
+ reset_to_rest_position();
+}
+
+const String &PhysicalBone::get_bone_name() const {
+
+ return bone_name;
+}
+
+void PhysicalBone::set_mass(real_t p_mass) {
+
+ ERR_FAIL_COND(p_mass <= 0);
+ mass = p_mass;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_MASS, mass);
+}
+
+real_t PhysicalBone::get_mass() const {
+
+ return mass;
+}
+
+void PhysicalBone::set_weight(real_t p_weight) {
+
+ set_mass(p_weight / real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8)));
+}
+
+real_t PhysicalBone::get_weight() const {
+
+ return mass * real_t(GLOBAL_DEF("physics/3d/default_gravity", 9.8));
+}
+
+void PhysicalBone::set_friction(real_t p_friction) {
+
+ ERR_FAIL_COND(p_friction < 0 || p_friction > 1);
+
+ friction = p_friction;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
+}
+
+real_t PhysicalBone::get_friction() const {
+
+ return friction;
+}
+
+void PhysicalBone::set_bounce(real_t p_bounce) {
+
+ ERR_FAIL_COND(p_bounce < 0 || p_bounce > 1);
+
+ bounce = p_bounce;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_BOUNCE, bounce);
+}
+real_t PhysicalBone::get_bounce() const {
+
+ return bounce;
+}
+
+void PhysicalBone::set_gravity_scale(real_t p_gravity_scale) {
+
+ gravity_scale = p_gravity_scale;
+ PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_GRAVITY_SCALE, gravity_scale);
+}
+
+real_t PhysicalBone::get_gravity_scale() const {
+
+ return gravity_scale;
+}
+
+PhysicalBone::PhysicalBone() :
+ PhysicsBody(PhysicsServer::BODY_MODE_STATIC),
+#ifdef TOOLS_ENABLED
+ gizmo_move_joint(false),
+#endif
+ joint_data(NULL),
+ static_body(false),
+ simulate_physics(false),
+ _internal_static_body(false),
+ _internal_simulate_physics(false),
+ bone_id(-1),
+ parent_skeleton(NULL),
+ bone_name(""),
+ bounce(0),
+ mass(1),
+ friction(1),
+ gravity_scale(1) {
+
+ set_static_body(static_body);
+ _reset_physics_simulation_state();
+}
+
+PhysicalBone::~PhysicalBone() {
+ memdelete(joint_data);
+}
+
+void PhysicalBone::update_bone_id() {
+ if (!parent_skeleton) {
+ return;
+ }
+
+ const int new_bone_id = parent_skeleton->find_bone(bone_name);
+
+ if (new_bone_id != bone_id) {
+ if (-1 != bone_id) {
+ // Assert the unbind from old node
+ parent_skeleton->unbind_physical_bone_from_bone(bone_id);
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ }
+
+ bone_id = new_bone_id;
+
+ parent_skeleton->bind_physical_bone_to_bone(bone_id, this);
+
+ _fix_joint_offset();
+ _internal_static_body = !static_body; // Force staticness reset
+ _reset_staticness_state();
+ }
+}
+
+void PhysicalBone::update_offset() {
+#ifdef TOOLS_ENABLED
+ if (parent_skeleton) {
+
+ Transform bone_transform(parent_skeleton->get_global_transform());
+ if (-1 != bone_id)
+ bone_transform *= parent_skeleton->get_bone_global_pose(bone_id);
+
+ if (gizmo_move_joint) {
+ bone_transform *= body_offset;
+ set_joint_offset(bone_transform.affine_inverse() * get_global_transform());
+ } else {
+ set_body_offset(bone_transform.affine_inverse() * get_global_transform());
+ }
+ }
+#endif
+}
+
+void PhysicalBone::reset_to_rest_position() {
+ if (parent_skeleton) {
+ if (-1 == bone_id) {
+ set_global_transform(parent_skeleton->get_global_transform() * body_offset);
+ } else {
+ set_global_transform(parent_skeleton->get_global_transform() * parent_skeleton->get_bone_global_pose(bone_id) * body_offset);
+ }
+ }
+}
+
+void PhysicalBone::_reset_physics_simulation_state() {
+ if (simulate_physics && !static_body) {
+ _start_physics_simulation();
+ } else {
+ _stop_physics_simulation();
+ }
+
+ _reset_staticness_state();
+}
+
+void PhysicalBone::_reset_staticness_state() {
+
+ if (parent_skeleton && -1 != bone_id) {
+ if (static_body && simulate_physics) { // With this check I'm sure the position of this body is updated only when it's necessary
+
+ if (_internal_static_body) {
+ return;
+ }
+
+ parent_skeleton->bind_child_node_to_bone(bone_id, this);
+ _internal_static_body = true;
+ } else {
+
+ if (!_internal_static_body) {
+ return;
+ }
+
+ parent_skeleton->unbind_child_node_from_bone(bone_id, this);
+ _internal_static_body = false;
+ }
+ }
+}
+
+void PhysicalBone::_start_physics_simulation() {
+ if (_internal_simulate_physics || !parent_skeleton) {
+ return;
+ }
+ reset_to_rest_position();
+ PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_RIGID);
+ PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), get_collision_layer());
+ PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), get_collision_mask());
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ parent_skeleton->set_bone_ignore_animation(bone_id, true);
+ _internal_simulate_physics = true;
+}
+
+void PhysicalBone::_stop_physics_simulation() {
+ if (!_internal_simulate_physics || !parent_skeleton) {
+ return;
+ }
+ PhysicsServer::get_singleton()->body_set_mode(get_rid(), PhysicsServer::BODY_MODE_STATIC);
+ PhysicsServer::get_singleton()->body_set_collision_layer(get_rid(), 0);
+ PhysicsServer::get_singleton()->body_set_collision_mask(get_rid(), 0);
+ PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), NULL, "");
+ parent_skeleton->set_bone_ignore_animation(bone_id, false);
+ _internal_simulate_physics = false;
+}
diff --git a/scene/3d/physics_body.h b/scene/3d/physics_body.h
index 9d9feda0b2..17d2769c79 100644
--- a/scene/3d/physics_body.h
+++ b/scene/3d/physics_body.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,11 +27,13 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PHYSICS_BODY__H
#define PHYSICS_BODY__H
#include "scene/3d/collision_object.h"
#include "servers/physics_server.h"
+#include "skeleton.h"
#include "vset.h"
class PhysicsBody : public CollisionObject {
@@ -114,7 +116,7 @@ public:
MODE_KINEMATIC,
};
-private:
+protected:
bool can_sleep;
PhysicsDirectBodyState *state;
Mode mode;
@@ -177,9 +179,8 @@ private:
void _body_exit_tree(ObjectID p_id);
void _body_inout(int p_status, ObjectID p_instance, int p_body_shape, int p_local_shape);
- void _direct_state_changed(Object *p_state);
+ virtual void _direct_state_changed(Object *p_state);
-protected:
void _notification(int p_what);
static void _bind_methods();
@@ -242,6 +243,7 @@ public:
Array get_colliding_bodies() const;
void apply_impulse(const Vector3 &p_pos, const Vector3 &p_impulse);
+ void apply_torque_impulse(const Vector3 &p_impulse);
virtual String get_configuration_warning() const;
@@ -285,15 +287,15 @@ private:
_FORCE_INLINE_ bool _ignores_mode(PhysicsServer::BodyMode) const;
- Ref<KinematicCollision> _move(const Vector3 &p_motion);
+ Ref<KinematicCollision> _move(const Vector3 &p_motion, bool p_infinite_inertia = true);
Ref<KinematicCollision> _get_slide_collision(int p_bounce);
protected:
static void _bind_methods();
public:
- bool move_and_collide(const Vector3 &p_motion, Collision &r_collision);
- bool test_move(const Transform &p_from, const Vector3 &p_motion);
+ bool move_and_collide(const Vector3 &p_motion, bool p_infinite_inertia, Collision &r_collision);
+ bool test_move(const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia);
void set_axis_lock(PhysicsServer::BodyAxis p_axis, bool p_lock);
bool get_axis_lock(PhysicsServer::BodyAxis p_axis) const;
@@ -301,7 +303,7 @@ public:
void set_safe_margin(float p_margin);
float get_safe_margin() const;
- Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
+ Vector3 move_and_slide(const Vector3 &p_linear_velocity, const Vector3 &p_floor_direction = Vector3(0, 0, 0), bool p_infinite_inertia = true, float p_slope_stop_min_velocity = 0.05, int p_max_slides = 4, float p_floor_max_angle = Math::deg2rad((float)45));
bool is_on_floor() const;
bool is_on_wall() const;
bool is_on_ceiling() const;
@@ -341,4 +343,267 @@ public:
KinematicCollision();
};
+class PhysicalBone : public PhysicsBody {
+
+ GDCLASS(PhysicalBone, PhysicsBody);
+
+public:
+ enum JointType {
+ JOINT_TYPE_NONE,
+ JOINT_TYPE_PIN,
+ JOINT_TYPE_CONE,
+ JOINT_TYPE_HINGE,
+ JOINT_TYPE_SLIDER,
+ JOINT_TYPE_6DOF
+ };
+
+ struct JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_NONE; }
+
+ /// "j" is used to set the parameter inside the PhysicsServer
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+ };
+
+ struct PinJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_PIN; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t bias;
+ real_t damping;
+ real_t impulse_clamp;
+
+ PinJointData() :
+ bias(0.3),
+ damping(1.),
+ impulse_clamp(0) {}
+ };
+
+ struct ConeJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_CONE; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t swing_span;
+ real_t twist_span;
+ real_t bias;
+ real_t softness;
+ real_t relaxation;
+
+ ConeJointData() :
+ swing_span(Math_PI * 0.25),
+ twist_span(Math_PI),
+ bias(0.3),
+ softness(0.8),
+ relaxation(1.) {}
+ };
+
+ struct HingeJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_HINGE; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ bool angular_limit_enabled;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_bias;
+ real_t angular_limit_softness;
+ real_t angular_limit_relaxation;
+
+ HingeJointData() :
+ angular_limit_enabled(false),
+ angular_limit_upper(Math_PI * 0.5),
+ angular_limit_lower(-Math_PI * 0.5),
+ angular_limit_bias(0.3),
+ angular_limit_softness(0.9),
+ angular_limit_relaxation(1.) {}
+ };
+
+ struct SliderJointData : public JointData {
+ virtual JointType get_joint_type() { return JOINT_TYPE_SLIDER; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ real_t linear_limit_upper;
+ real_t linear_limit_lower;
+ real_t linear_limit_softness;
+ real_t linear_limit_restitution;
+ real_t linear_limit_damping;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_softness;
+ real_t angular_limit_restitution;
+ real_t angular_limit_damping;
+
+ SliderJointData() :
+ linear_limit_upper(1.),
+ linear_limit_lower(-1.),
+ linear_limit_softness(1.),
+ linear_limit_restitution(0.7),
+ linear_limit_damping(1.),
+ angular_limit_upper(0),
+ angular_limit_lower(0),
+ angular_limit_softness(1.),
+ angular_limit_restitution(0.7),
+ angular_limit_damping(1.) {}
+ };
+
+ struct SixDOFJointData : public JointData {
+ struct SixDOFAxisData {
+ bool linear_limit_enabled;
+ real_t linear_limit_upper;
+ real_t linear_limit_lower;
+ real_t linear_limit_softness;
+ real_t linear_restitution;
+ real_t linear_damping;
+ bool angular_limit_enabled;
+ real_t angular_limit_upper;
+ real_t angular_limit_lower;
+ real_t angular_limit_softness;
+ real_t angular_restitution;
+ real_t angular_damping;
+ real_t erp;
+
+ SixDOFAxisData() :
+ linear_limit_enabled(true),
+ linear_limit_upper(0),
+ linear_limit_lower(0),
+ linear_limit_softness(0.7),
+ linear_restitution(0.5),
+ linear_damping(1.),
+ angular_limit_enabled(true),
+ angular_limit_upper(0),
+ angular_limit_lower(0),
+ angular_limit_softness(0.5),
+ angular_restitution(0),
+ angular_damping(1.),
+ erp(0.5) {}
+ };
+
+ virtual JointType get_joint_type() { return JOINT_TYPE_6DOF; }
+
+ virtual bool _set(const StringName &p_name, const Variant &p_value, RID j = RID());
+ virtual bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _get_property_list(List<PropertyInfo> *p_list) const;
+
+ SixDOFAxisData axis_data[3];
+
+ SixDOFJointData() {}
+ };
+
+private:
+#ifdef TOOLS_ENABLED
+ // if false gizmo move body
+ bool gizmo_move_joint;
+#endif
+
+ JointData *joint_data;
+ Transform joint_offset;
+ RID joint;
+
+ Skeleton *parent_skeleton;
+ Transform body_offset;
+ Transform body_offset_inverse;
+ bool static_body;
+ bool _internal_static_body;
+ bool simulate_physics;
+ bool _internal_simulate_physics;
+ int bone_id;
+
+ String bone_name;
+ real_t bounce;
+ real_t mass;
+ real_t friction;
+ real_t gravity_scale;
+
+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;
+ void _notification(int p_what);
+ void _direct_state_changed(Object *p_state);
+
+ static void _bind_methods();
+
+private:
+ static Skeleton *find_skeleton_parent(Node *p_parent);
+ void _fix_joint_offset();
+ void _reload_joint();
+
+public:
+ void _on_bone_parent_changed();
+ void _set_gizmo_move_joint(bool p_move_joint);
+
+public:
+#ifdef TOOLS_ENABLED
+ virtual Transform get_global_gizmo_transform() const;
+ virtual Transform get_local_gizmo_transform() const;
+#endif
+
+ const JointData *get_joint_data() const;
+ Skeleton *find_skeleton_parent();
+
+ int get_bone_id() const { return bone_id; }
+
+ void set_joint_type(JointType p_joint_type);
+ JointType get_joint_type() const;
+
+ void set_joint_offset(const Transform &p_offset);
+ const Transform &get_joint_offset() const;
+
+ void set_body_offset(const Transform &p_offset);
+ const Transform &get_body_offset() const;
+
+ void set_static_body(bool p_static);
+ bool is_static_body();
+
+ void set_simulate_physics(bool p_simulate);
+ bool get_simulate_physics();
+ bool is_simulating_physics();
+
+ void set_bone_name(const String &p_name);
+ const String &get_bone_name() const;
+
+ void set_mass(real_t p_mass);
+ real_t get_mass() const;
+
+ void set_weight(real_t p_weight);
+ real_t get_weight() const;
+
+ void set_friction(real_t p_friction);
+ real_t get_friction() const;
+
+ 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;
+
+ PhysicalBone();
+ ~PhysicalBone();
+
+private:
+ void update_bone_id();
+ void update_offset();
+ void reset_to_rest_position();
+
+ void _reset_physics_simulation_state();
+ void _reset_staticness_state();
+
+ void _start_physics_simulation();
+ void _stop_physics_simulation();
+};
+
+VARIANT_ENUM_CAST(PhysicalBone::JointType);
+
#endif // PHYSICS_BODY__H
diff --git a/scene/3d/physics_joint.cpp b/scene/3d/physics_joint.cpp
index 1d779d31fe..b2d10006f7 100644
--- a/scene/3d/physics_joint.cpp
+++ b/scene/3d/physics_joint.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "physics_joint.h"
void Joint::_update_joint(bool p_only_free) {
@@ -70,8 +71,7 @@ void Joint::_update_joint(bool p_only_free) {
ba = body_a->get_rid();
bb = body_b->get_rid();
- if (exclude_from_collision)
- PhysicsServer::get_singleton()->body_add_collision_exception(body_a->get_rid(), body_b->get_rid());
+ PhysicsServer::get_singleton()->joint_disable_collisions_between_bodies(joint, exclude_from_collision);
}
void Joint::set_node_a(const NodePath &p_node_a) {
@@ -716,6 +716,9 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_x/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_x", "get_param_x", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/target_velocity"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_x/force_limit"), "set_param_x", "get_param_x", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_x/enabled"), "set_flag_x", "get_flag_x", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_x/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_x", "_get_angular_hi_limit_x");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_x/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_x", "_get_angular_lo_limit_x");
@@ -734,6 +737,9 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_y/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_y", "get_param_y", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/target_velocity"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_y/force_limit"), "set_param_y", "get_param_y", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_y/enabled"), "set_flag_y", "get_flag_y", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_y/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_y", "_get_angular_hi_limit_y");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_y/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_y", "_get_angular_lo_limit_y");
@@ -752,6 +758,9 @@ void Generic6DOFJoint::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/softness", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_LIMIT_SOFTNESS);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/restitution", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_RESTITUTION);
ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_limit_z/damping", PROPERTY_HINT_RANGE, "0.01,16,0.01"), "set_param_z", "get_param_z", PARAM_LINEAR_DAMPING);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "linear_motor_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_LINEAR_MOTOR);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/target_velocity"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ ADD_PROPERTYI(PropertyInfo(Variant::REAL, "linear_motor_z/force_limit"), "set_param_z", "get_param_z", PARAM_LINEAR_MOTOR_FORCE_LIMIT);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "angular_limit_z/enabled"), "set_flag_z", "get_flag_z", FLAG_ENABLE_ANGULAR_LIMIT);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_z/upper_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_hi_limit_z", "_get_angular_hi_limit_z");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "angular_limit_z/lower_angle", PROPERTY_HINT_RANGE, "-180,180,0.01"), "_set_angular_lo_limit_z", "_get_angular_lo_limit_z");
@@ -769,6 +778,8 @@ void Generic6DOFJoint::_bind_methods() {
BIND_ENUM_CONSTANT(PARAM_LINEAR_LIMIT_SOFTNESS);
BIND_ENUM_CONSTANT(PARAM_LINEAR_RESTITUTION);
BIND_ENUM_CONSTANT(PARAM_LINEAR_DAMPING);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_TARGET_VELOCITY);
+ BIND_ENUM_CONSTANT(PARAM_LINEAR_MOTOR_FORCE_LIMIT);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(PARAM_ANGULAR_LIMIT_SOFTNESS);
@@ -783,6 +794,7 @@ void Generic6DOFJoint::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_LIMIT);
BIND_ENUM_CONSTANT(FLAG_ENABLE_ANGULAR_LIMIT);
BIND_ENUM_CONSTANT(FLAG_ENABLE_MOTOR);
+ BIND_ENUM_CONSTANT(FLAG_ENABLE_LINEAR_MOTOR);
BIND_ENUM_CONSTANT(FLAG_MAX);
}
@@ -912,6 +924,8 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_param_x(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
set_param_x(PARAM_LINEAR_RESTITUTION, 0.5);
set_param_x(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_x(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_x(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
set_param_x(PARAM_ANGULAR_LOWER_LIMIT, 0);
set_param_x(PARAM_ANGULAR_UPPER_LIMIT, 0);
set_param_x(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
@@ -925,12 +939,15 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_flag_x(FLAG_ENABLE_ANGULAR_LIMIT, true);
set_flag_x(FLAG_ENABLE_LINEAR_LIMIT, true);
set_flag_x(FLAG_ENABLE_MOTOR, false);
+ set_flag_x(FLAG_ENABLE_LINEAR_MOTOR, false);
set_param_y(PARAM_LINEAR_LOWER_LIMIT, 0);
set_param_y(PARAM_LINEAR_UPPER_LIMIT, 0);
set_param_y(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
set_param_y(PARAM_LINEAR_RESTITUTION, 0.5);
set_param_y(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_y(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_y(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
set_param_y(PARAM_ANGULAR_LOWER_LIMIT, 0);
set_param_y(PARAM_ANGULAR_UPPER_LIMIT, 0);
set_param_y(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
@@ -944,12 +961,15 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_flag_y(FLAG_ENABLE_ANGULAR_LIMIT, true);
set_flag_y(FLAG_ENABLE_LINEAR_LIMIT, true);
set_flag_y(FLAG_ENABLE_MOTOR, false);
+ set_flag_y(FLAG_ENABLE_LINEAR_MOTOR, false);
set_param_z(PARAM_LINEAR_LOWER_LIMIT, 0);
set_param_z(PARAM_LINEAR_UPPER_LIMIT, 0);
set_param_z(PARAM_LINEAR_LIMIT_SOFTNESS, 0.7);
set_param_z(PARAM_LINEAR_RESTITUTION, 0.5);
set_param_z(PARAM_LINEAR_DAMPING, 1.0);
+ set_param_z(PARAM_LINEAR_MOTOR_TARGET_VELOCITY, 0);
+ set_param_z(PARAM_LINEAR_MOTOR_FORCE_LIMIT, 0);
set_param_z(PARAM_ANGULAR_LOWER_LIMIT, 0);
set_param_z(PARAM_ANGULAR_UPPER_LIMIT, 0);
set_param_z(PARAM_ANGULAR_LIMIT_SOFTNESS, 0.5f);
@@ -963,4 +983,5 @@ Generic6DOFJoint::Generic6DOFJoint() {
set_flag_z(FLAG_ENABLE_ANGULAR_LIMIT, true);
set_flag_z(FLAG_ENABLE_LINEAR_LIMIT, true);
set_flag_z(FLAG_ENABLE_MOTOR, false);
+ set_flag_z(FLAG_ENABLE_LINEAR_MOTOR, false);
}
diff --git a/scene/3d/physics_joint.h b/scene/3d/physics_joint.h
index b94297da30..37870d6f30 100644
--- a/scene/3d/physics_joint.h
+++ b/scene/3d/physics_joint.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PHYSICS_JOINT_H
#define PHYSICS_JOINT_H
@@ -248,6 +249,8 @@ public:
PARAM_LINEAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_LINEAR_LIMIT_SOFTNESS,
PARAM_LINEAR_RESTITUTION = PhysicsServer::G6DOF_JOINT_LINEAR_RESTITUTION,
PARAM_LINEAR_DAMPING = PhysicsServer::G6DOF_JOINT_LINEAR_DAMPING,
+ PARAM_LINEAR_MOTOR_TARGET_VELOCITY = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY,
+ PARAM_LINEAR_MOTOR_FORCE_LIMIT = PhysicsServer::G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT,
PARAM_ANGULAR_LOWER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_LOWER_LIMIT,
PARAM_ANGULAR_UPPER_LIMIT = PhysicsServer::G6DOF_JOINT_ANGULAR_UPPER_LIMIT,
PARAM_ANGULAR_LIMIT_SOFTNESS = PhysicsServer::G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS,
@@ -264,6 +267,7 @@ public:
FLAG_ENABLE_LINEAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT,
FLAG_ENABLE_ANGULAR_LIMIT = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT,
FLAG_ENABLE_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_MOTOR,
+ FLAG_ENABLE_LINEAR_MOTOR = PhysicsServer::G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR,
FLAG_MAX = PhysicsServer::G6DOF_JOINT_FLAG_MAX
};
diff --git a/scene/3d/portal.cpp b/scene/3d/portal.cpp
index 4fde29aab9..d16d9ed7c5 100644
--- a/scene/3d/portal.cpp
+++ b/scene/3d/portal.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "portal.h"
#include "project_settings.h"
#include "scene/resources/surface_tool.h"
diff --git a/scene/3d/portal.h b/scene/3d/portal.h
index 4ea208a718..cb3f208072 100644
--- a/scene/3d/portal.h
+++ b/scene/3d/portal.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PORTAL_H
#define PORTAL_H
@@ -39,7 +40,8 @@
If a portal is placed next (very close to) a similar, opposing portal, they automatically connect,
otherwise, a portal connects to the parent room
*/
-//this will be redone and replaced by area portals, left for reference since a new class with this name will have to exist and want to reuse the gizmos
+// FIXME: This will be redone and replaced by area portals, left for reference
+// since a new class with this name will have to exist and want to reuse the gizmos
#if 0
class Portal : public VisualInstance {
diff --git a/scene/3d/position_3d.cpp b/scene/3d/position_3d.cpp
index d0df985ac4..3ae04f491f 100644
--- a/scene/3d/position_3d.cpp
+++ b/scene/3d/position_3d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "position_3d.h"
#include "scene/resources/mesh.h"
diff --git a/scene/3d/position_3d.h b/scene/3d/position_3d.h
index 8083c33196..2bc69eff9b 100644
--- a/scene/3d/position_3d.h
+++ b/scene/3d/position_3d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef POSITION_3D_H
#define POSITION_3D_H
diff --git a/scene/3d/proximity_group.cpp b/scene/3d/proximity_group.cpp
index 2288d8b08b..101d9ed70c 100644
--- a/scene/3d/proximity_group.cpp
+++ b/scene/3d/proximity_group.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "proximity_group.h"
#include "math_funcs.h"
@@ -111,11 +112,6 @@ void ProximityGroup::_new_group(StringName p_name) {
groups[p_name] = group_version;
};
-void ProximityGroup::set_group_name(String p_group_name) {
-
- group_name = p_group_name;
-};
-
void ProximityGroup::_notification(int p_what) {
switch (p_what) {
@@ -152,9 +148,24 @@ void ProximityGroup::_proximity_group_broadcast(String p_name, Variant p_params)
};
};
-void ProximityGroup::set_dispatch_mode(int p_mode) {
+void ProximityGroup::set_group_name(const String &p_group_name) {
+
+ group_name = p_group_name;
+};
+
+String ProximityGroup::get_group_name() const {
+
+ return group_name;
+};
+
+void ProximityGroup::set_dispatch_mode(DispatchMode p_mode) {
+
+ dispatch_mode = p_mode;
+};
+
+ProximityGroup::DispatchMode ProximityGroup::get_dispatch_mode() const {
- dispatch_mode = (DispatchMode)p_mode;
+ return dispatch_mode;
};
void ProximityGroup::set_grid_radius(const Vector3 &p_radius) {
@@ -170,15 +181,22 @@ Vector3 ProximityGroup::get_grid_radius() const {
void ProximityGroup::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_group_name", "name"), &ProximityGroup::set_group_name);
- ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup::broadcast);
+ ClassDB::bind_method(D_METHOD("get_group_name"), &ProximityGroup::get_group_name);
ClassDB::bind_method(D_METHOD("set_dispatch_mode", "mode"), &ProximityGroup::set_dispatch_mode);
- ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup::_proximity_group_broadcast);
+ ClassDB::bind_method(D_METHOD("get_dispatch_mode"), &ProximityGroup::get_dispatch_mode);
ClassDB::bind_method(D_METHOD("set_grid_radius", "radius"), &ProximityGroup::set_grid_radius);
ClassDB::bind_method(D_METHOD("get_grid_radius"), &ProximityGroup::get_grid_radius);
+ ClassDB::bind_method(D_METHOD("broadcast", "name", "parameters"), &ProximityGroup::broadcast);
+ ClassDB::bind_method(D_METHOD("_proximity_group_broadcast", "name", "params"), &ProximityGroup::_proximity_group_broadcast);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "group_name"), "set_group_name", "get_group_name");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "dispatch_mode", PROPERTY_HINT_ENUM, "Proxy,Signal"), "set_dispatch_mode", "get_dispatch_mode");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "grid_radius"), "set_grid_radius", "get_grid_radius");
- ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::ARRAY, "parameters")));
+ ADD_SIGNAL(MethodInfo("broadcast", PropertyInfo(Variant::STRING, "group_name"), PropertyInfo(Variant::ARRAY, "parameters")));
+
+ BIND_ENUM_CONSTANT(MODE_PROXY);
+ BIND_ENUM_CONSTANT(MODE_SIGNAL);
};
ProximityGroup::ProximityGroup() {
diff --git a/scene/3d/proximity_group.h b/scene/3d/proximity_group.h
index d003d2f525..448f30bf80 100644
--- a/scene/3d/proximity_group.h
+++ b/scene/3d/proximity_group.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PROXIMITY_GROUP_H
#define PROXIMITY_GROUP_H
@@ -66,15 +67,21 @@ public:
static void _bind_methods();
public:
- void set_group_name(String p_group_name);
- void broadcast(String p_name, Variant p_params);
- void set_dispatch_mode(int p_mode);
+ void set_group_name(const String &p_group_name);
+ String get_group_name() const;
+
+ void set_dispatch_mode(DispatchMode p_mode);
+ DispatchMode get_dispatch_mode() const;
void set_grid_radius(const Vector3 &p_radius);
Vector3 get_grid_radius() const;
+ void broadcast(String p_name, Variant p_params);
+
ProximityGroup();
~ProximityGroup();
};
+VARIANT_ENUM_CAST(ProximityGroup::DispatchMode);
+
#endif
diff --git a/scene/3d/ray_cast.cpp b/scene/3d/ray_cast.cpp
index faeb18691a..7f83e2c3ea 100644
--- a/scene/3d/ray_cast.cpp
+++ b/scene/3d/ray_cast.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "ray_cast.h"
#include "collision_object.h"
@@ -102,7 +103,7 @@ void RayCast::set_enabled(bool p_enabled) {
enabled = p_enabled;
if (is_inside_tree() && !Engine::get_singleton()->is_editor_hint())
- set_physics_process(p_enabled);
+ set_physics_process_internal(p_enabled);
if (!p_enabled)
collided = false;
@@ -149,12 +150,12 @@ void RayCast::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
if (enabled && !Engine::get_singleton()->is_editor_hint()) {
- set_physics_process(true);
+ set_physics_process_internal(true);
if (get_tree()->is_debugging_collisions_hint())
_update_debug_shape();
} else
- set_physics_process(false);
+ set_physics_process_internal(false);
if (Object::cast_to<CollisionObject>(get_parent())) {
if (exclude_parent_body)
@@ -167,14 +168,14 @@ void RayCast::_notification(int p_what) {
case NOTIFICATION_EXIT_TREE: {
if (enabled) {
- set_physics_process(false);
+ set_physics_process_internal(false);
}
if (debug_shape)
_clear_debug_shape();
} break;
- case NOTIFICATION_PHYSICS_PROCESS: {
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
if (!enabled)
break;
@@ -216,6 +217,8 @@ void RayCast::_update_raycast_state() {
against_shape = rr.shape;
} else {
collided = false;
+ against = 0;
+ against_shape = 0;
}
}
diff --git a/scene/3d/ray_cast.h b/scene/3d/ray_cast.h
index 9fb1a1be67..20cea80700 100644
--- a/scene/3d/ray_cast.h
+++ b/scene/3d/ray_cast.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RAY_CAST_H
#define RAY_CAST_H
diff --git a/scene/3d/reflection_probe.cpp b/scene/3d/reflection_probe.cpp
index 0e575ec152..7e3a87cbd4 100644
--- a/scene/3d/reflection_probe.cpp
+++ b/scene/3d/reflection_probe.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "reflection_probe.h"
void ReflectionProbe::set_intensity(float p_intensity) {
@@ -194,7 +195,7 @@ void ReflectionProbe::_validate_property(PropertyInfo &property) const {
if (property.name == "interior/ambient_color" || property.name == "interior/ambient_energy" || property.name == "interior/ambient_contrib") {
if (!interior) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
}
}
@@ -239,7 +240,7 @@ void ReflectionProbe::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "update_mode", PROPERTY_HINT_ENUM, "Once,Always"), "set_update_mode", "get_update_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "intensity", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_intensity", "get_intensity");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_RANGE, "0,16384,0.1"), "set_max_distance", "get_max_distance");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_distance", PROPERTY_HINT_EXP_RANGE, "0,16384,0.1,or_greater"), "set_max_distance", "get_max_distance");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "extents"), "set_extents", "get_extents");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "origin_offset"), "set_origin_offset", "get_origin_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "box_projection"), "set_enable_box_projection", "is_box_projection_enabled");
diff --git a/scene/3d/reflection_probe.h b/scene/3d/reflection_probe.h
index 26f17fdcf9..13ae1c81f6 100644
--- a/scene/3d/reflection_probe.h
+++ b/scene/3d/reflection_probe.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef REFLECTIONPROBE_H
#define REFLECTIONPROBE_H
diff --git a/scene/3d/remote_transform.cpp b/scene/3d/remote_transform.cpp
index 8faf985b11..afb85f7314 100644
--- a/scene/3d/remote_transform.cpp
+++ b/scene/3d/remote_transform.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/3d/remote_transform.h b/scene/3d/remote_transform.h
index 51a0bf35a3..6b788a2d75 100644
--- a/scene/3d/remote_transform.h
+++ b/scene/3d/remote_transform.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef REMOTETRANSFORM_H
#define REMOTETRANSFORM_H
diff --git a/scene/3d/room_instance.cpp b/scene/3d/room_instance.cpp
index 47a7b8bfb9..0d83a9942e 100644
--- a/scene/3d/room_instance.cpp
+++ b/scene/3d/room_instance.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "room_instance.h"
#include "servers/visual_server.h"
diff --git a/scene/3d/room_instance.h b/scene/3d/room_instance.h
index 3069ea2eba..ff388e606c 100644
--- a/scene/3d/room_instance.h
+++ b/scene/3d/room_instance.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ROOM_INSTANCE_H
#define ROOM_INSTANCE_H
@@ -44,7 +45,7 @@
*/
-//this will be removed, left for reference
+// FIXME: this will be removed, left for reference
#if 0
class Room : public VisualInstance {
diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp
index 8102b3f15c..26cbfc0b11 100644
--- a/scene/3d/scenario_fx.cpp
+++ b/scene/3d/scenario_fx.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "scenario_fx.h"
#include "scene/main/viewport.h"
@@ -78,7 +79,11 @@ Ref<Environment> WorldEnvironment::get_environment() const {
String WorldEnvironment::get_configuration_warning() const {
- if (/*!is_visible_in_tree() ||*/ !is_inside_tree() || !environment.is_valid())
+ if (!environment.is_valid()) {
+ return TTR("WorldEnvironment needs an Environment resource.");
+ }
+
+ if (/*!is_visible_in_tree() ||*/ !is_inside_tree())
return String();
List<Node *> nodes;
@@ -88,6 +93,11 @@ String WorldEnvironment::get_configuration_warning() const {
return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes).");
}
+ // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated.
+ //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) {
+ // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes).");
+ //}
+
return String();
}
diff --git a/scene/3d/scenario_fx.h b/scene/3d/scenario_fx.h
index acf6a18526..7a8e2b548f 100644
--- a/scene/3d/scenario_fx.h
+++ b/scene/3d/scenario_fx.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCENARIO_FX_H
#define SCENARIO_FX_H
diff --git a/scene/3d/skeleton.cpp b/scene/3d/skeleton.cpp
index d0e0937eca..76d90dc6ff 100644
--- a/scene/3d/skeleton.cpp
+++ b/scene/3d/skeleton.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,11 +27,13 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "skeleton.h"
#include "message_queue.h"
#include "core/project_settings.h"
+#include "scene/3d/physics_body.h"
#include "scene/resources/surface_tool.h"
bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
@@ -60,7 +62,7 @@ bool Skeleton::_set(const StringName &p_path, const Variant &p_value) {
set_bone_enabled(which, p_value);
else if (what == "pose")
set_bone_pose(which, p_value);
- else if (what == "bound_childs") {
+ else if (what == "bound_children") {
Array children = p_value;
if (is_inside_tree()) {
@@ -104,7 +106,7 @@ bool Skeleton::_get(const StringName &p_path, Variant &r_ret) const {
r_ret = is_bone_enabled(which);
else if (what == "pose")
r_ret = get_bone_pose(which);
- else if (what == "bound_childs") {
+ else if (what == "bound_children") {
Array children;
for (const List<uint32_t>::Element *E = bones[which].nodes_bound.front(); E; E = E->next()) {
@@ -133,7 +135,7 @@ void Skeleton::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "rest"));
p_list->push_back(PropertyInfo(Variant::BOOL, prep + "enabled"));
p_list->push_back(PropertyInfo(Variant::TRANSFORM, prep + "pose", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_childs"));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, prep + "bound_children"));
}
}
@@ -153,6 +155,24 @@ void Skeleton::_notification(int p_what) {
case NOTIFICATION_EXIT_WORLD: {
} break;
+ case NOTIFICATION_TRANSFORM_CHANGED: {
+
+ if (dirty)
+ break; //will be eventually updated
+
+ //if moved, just update transforms
+ VisualServer *vs = VisualServer::get_singleton();
+ const Bone *bonesptr = bones.ptr();
+ int len = bones.size();
+ Transform global_transform = get_global_transform();
+ Transform global_transform_inverse = global_transform.affine_inverse();
+
+ for (int i = 0; i < len; i++) {
+
+ const Bone &b = bonesptr[i];
+ vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));
+ }
+ } break;
case NOTIFICATION_UPDATE_SKELETON: {
VisualServer *vs = VisualServer::get_singleton();
@@ -180,6 +200,9 @@ void Skeleton::_notification(int p_what) {
rest_global_inverse_dirty = false;
}
+ Transform global_transform = get_global_transform();
+ Transform global_transform_inverse = global_transform.affine_inverse();
+
for (int i = 0; i < len; i++) {
Bone &b = bonesptr[i];
@@ -239,7 +262,8 @@ void Skeleton::_notification(int p_what) {
}
}
- vs->skeleton_bone_set_transform(skeleton, i, b.pose_global * b.rest_global_inverse);
+ b.transform_final = b.pose_global * b.rest_global_inverse;
+ vs->skeleton_bone_set_transform(skeleton, i, global_transform * (b.transform_final * global_transform_inverse));
for (List<uint32_t>::Element *E = b.nodes_bound.front(); E; E = E->next()) {
@@ -306,7 +330,7 @@ void Skeleton::add_bone(const String &p_name) {
_make_dirty();
update_gizmo();
}
-int Skeleton::find_bone(String p_name) const {
+int Skeleton::find_bone(const String &p_name) const {
for (int i = 0; i < bones.size(); i++) {
@@ -323,6 +347,19 @@ String Skeleton::get_bone_name(int p_bone) const {
return bones[p_bone].name;
}
+bool Skeleton::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
+
+ int parent_of_bone = get_bone_parent(p_bone);
+
+ if (-1 == parent_of_bone)
+ return false;
+
+ if (parent_of_bone == p_parent_bone_id)
+ return true;
+
+ return is_bone_parent_of(parent_of_bone, p_parent_bone_id);
+}
+
int Skeleton::get_bone_count() const {
return bones.size();
@@ -354,6 +391,17 @@ void Skeleton::unparent_bone_and_rest(int p_bone) {
_make_dirty();
}
+void Skeleton::set_bone_ignore_animation(int p_bone, bool p_ignore) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones[p_bone].ignore_animation = p_ignore;
+}
+
+bool Skeleton::is_bone_ignore_animation(int p_bone) const {
+
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), false);
+ return bones[p_bone].ignore_animation;
+}
+
void Skeleton::set_bone_disable_rest(int p_bone, bool p_disable) {
ERR_FAIL_INDEX(p_bone, bones.size());
@@ -499,6 +547,150 @@ void Skeleton::localize_rests() {
}
}
+void Skeleton::bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ ERR_FAIL_COND(bones[p_bone].physical_bone);
+ ERR_FAIL_COND(!p_physical_bone);
+ bones[p_bone].physical_bone = p_physical_bone;
+
+ _rebuild_physical_bones_cache();
+}
+
+void Skeleton::unbind_physical_bone_from_bone(int p_bone) {
+ ERR_FAIL_INDEX(p_bone, bones.size());
+ bones[p_bone].physical_bone = NULL;
+
+ _rebuild_physical_bones_cache();
+}
+
+PhysicalBone *Skeleton::get_physical_bone(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
+
+ return bones[p_bone].physical_bone;
+}
+
+PhysicalBone *Skeleton::get_physical_bone_parent(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
+
+ if (bones[p_bone].cache_parent_physical_bone) {
+ return bones[p_bone].cache_parent_physical_bone;
+ }
+
+ return _get_physical_bone_parent(p_bone);
+}
+
+PhysicalBone *Skeleton::_get_physical_bone_parent(int p_bone) {
+ ERR_FAIL_INDEX_V(p_bone, bones.size(), NULL);
+
+ const int parent_bone = bones[p_bone].parent;
+ if (0 > parent_bone) {
+ return NULL;
+ }
+
+ PhysicalBone *pb = bones[parent_bone].physical_bone;
+ if (pb) {
+ return pb;
+ } else {
+ return get_physical_bone_parent(parent_bone);
+ }
+}
+
+void Skeleton::_rebuild_physical_bones_cache() {
+ const int b_size = bones.size();
+ for (int i = 0; i < b_size; ++i) {
+ bones[i].cache_parent_physical_bone = _get_physical_bone_parent(i);
+ if (bones[i].physical_bone)
+ bones[i].physical_bone->_on_bone_parent_changed();
+ }
+}
+
+void _pb_stop_simulation(Node *p_node) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_stop_simulation(p_node->get_child(i));
+ }
+
+ PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+ if (pb) {
+ pb->set_simulate_physics(false);
+ pb->set_static_body(false);
+ }
+}
+
+void Skeleton::physical_bones_stop_simulation() {
+ _pb_stop_simulation(this);
+}
+
+void _pb_start_simulation(const Skeleton *p_skeleton, Node *p_node, const Vector<int> &p_sim_bones) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _pb_start_simulation(p_skeleton, p_node->get_child(i), p_sim_bones);
+ }
+
+ PhysicalBone *pb = Object::cast_to<PhysicalBone>(p_node);
+ if (pb) {
+ bool sim = false;
+ for (int i = p_sim_bones.size() - 1; 0 <= i; --i) {
+ if (p_sim_bones[i] == pb->get_bone_id() || p_skeleton->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
+ sim = true;
+ break;
+ }
+ }
+
+ pb->set_simulate_physics(true);
+ if (sim) {
+ pb->set_static_body(false);
+ } else {
+ pb->set_static_body(true);
+ }
+ }
+}
+
+void Skeleton::physical_bones_start_simulation_on(const Array &p_bones) {
+
+ Vector<int> sim_bones;
+ if (p_bones.size() <= 0) {
+ sim_bones.push_back(0); // if no bones is specified, activate ragdoll on full body
+ } else {
+ sim_bones.resize(p_bones.size());
+ int c = 0;
+ for (int i = sim_bones.size() - 1; 0 <= i; --i) {
+ if (Variant::STRING == p_bones.get(i).get_type()) {
+ int bone_id = find_bone(p_bones.get(i));
+ if (bone_id != -1)
+ sim_bones[c++] = bone_id;
+ }
+ }
+ sim_bones.resize(c);
+ }
+
+ _pb_start_simulation(this, this, sim_bones);
+}
+
+void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
+
+ for (int i = p_node->get_child_count() - 1; 0 <= i; --i) {
+ _physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception);
+ }
+
+ CollisionObject *co = Object::cast_to<CollisionObject>(p_node);
+ if (co) {
+ if (p_add) {
+ PhysicsServer::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception);
+ } else {
+ PhysicsServer::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception);
+ }
+ }
+}
+
+void Skeleton::physical_bones_add_collision_exception(RID p_exception) {
+ _physical_bones_add_remove_collision_exception(true, this, p_exception);
+}
+
+void Skeleton::physical_bones_remove_collision_exception(RID p_exception) {
+ _physical_bones_add_remove_collision_exception(false, this, p_exception);
+}
+
void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_bone", "name"), &Skeleton::add_bone);
@@ -535,6 +727,11 @@ void Skeleton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_transform", "bone_idx"), &Skeleton::get_bone_transform);
+ ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &Skeleton::physical_bones_stop_simulation);
+ ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &Skeleton::physical_bones_start_simulation_on, DEFVAL(Array()));
+ ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton::physical_bones_add_collision_exception);
+ ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton::physical_bones_remove_collision_exception);
+
BIND_CONSTANT(NOTIFICATION_UPDATE_SKELETON);
}
@@ -543,9 +740,9 @@ Skeleton::Skeleton() {
rest_global_inverse_dirty = true;
dirty = false;
skeleton = VisualServer::get_singleton()->skeleton_create();
+ set_notify_transform(true);
}
Skeleton::~Skeleton() {
-
VisualServer::get_singleton()->free(skeleton);
}
diff --git a/scene/3d/skeleton.h b/scene/3d/skeleton.h
index fdc1100472..dad11960a5 100644
--- a/scene/3d/skeleton.h
+++ b/scene/3d/skeleton.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SKELETON_H
#define SKELETON_H
@@ -36,6 +37,8 @@
/**
@author Juan Linietsky <reduzio@gmail.com>
*/
+
+class PhysicalBone;
class Skeleton : public Spatial {
GDCLASS(Skeleton, Spatial);
@@ -47,6 +50,8 @@ class Skeleton : public Spatial {
bool enabled;
int parent;
+ bool ignore_animation;
+
bool disable_rest;
Transform rest;
Transform rest_global_inverse;
@@ -57,13 +62,21 @@ class Skeleton : public Spatial {
bool custom_pose_enable;
Transform custom_pose;
+ Transform transform_final;
+
+ PhysicalBone *physical_bone;
+ PhysicalBone *cache_parent_physical_bone;
+
List<uint32_t> nodes_bound;
Bone() {
parent = -1;
enabled = true;
+ ignore_animation = false;
custom_pose_enable = false;
disable_rest = false;
+ physical_bone = NULL;
+ cache_parent_physical_bone = NULL;
}
};
@@ -80,12 +93,12 @@ class Skeleton : public Spatial {
Array _get_bound_child_nodes_to_bone(int p_bone) const {
Array bound;
- List<Node *> childs;
- get_bound_child_nodes_to_bone(p_bone, &childs);
+ List<Node *> children;
+ get_bound_child_nodes_to_bone(p_bone, &children);
- for (int i = 0; i < childs.size(); i++) {
+ for (int i = 0; i < children.size(); i++) {
- bound.push_back(childs[i]);
+ bound.push_back(children[i]);
}
return bound;
}
@@ -107,14 +120,19 @@ public:
// skeleton creation api
void add_bone(const String &p_name);
- int find_bone(String p_name) const;
+ int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
+ bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
+
void set_bone_parent(int p_bone, int p_parent);
int get_bone_parent(int p_bone) const;
void unparent_bone_and_rest(int p_bone);
+ void set_bone_ignore_animation(int p_bone, bool p_ignore);
+ bool is_bone_ignore_animation(int p_bone) const;
+
void set_bone_disable_rest(int p_bone, bool p_disable);
bool is_bone_rest_disabled(int p_bone) const;
@@ -146,6 +164,26 @@ public:
void localize_rests(); // used for loaders and tools
+ // Physical bone API
+
+ void bind_physical_bone_to_bone(int p_bone, PhysicalBone *p_physical_bone);
+ void unbind_physical_bone_from_bone(int p_bone);
+
+ PhysicalBone *get_physical_bone(int p_bone);
+ PhysicalBone *get_physical_bone_parent(int p_bone);
+
+private:
+ /// This is a slow API os it's cached
+ PhysicalBone *_get_physical_bone_parent(int p_bone);
+ void _rebuild_physical_bones_cache();
+
+public:
+ void physical_bones_stop_simulation();
+ void physical_bones_start_simulation_on(const Array &p_bones);
+ void physical_bones_add_collision_exception(RID p_exception);
+ void physical_bones_remove_collision_exception(RID p_exception);
+
+public:
Skeleton();
~Skeleton();
};
diff --git a/scene/3d/spatial.cpp b/scene/3d/spatial.cpp
index d9f88ac693..748aa8aad4 100644
--- a/scene/3d/spatial.cpp
+++ b/scene/3d/spatial.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "spatial.h"
#include "engine.h"
@@ -84,9 +85,7 @@ void Spatial::_notify_dirty() {
}
void Spatial::_update_local_transform() const {
- data.local_transform.basis = Basis();
- data.local_transform.basis.scale(data.scale);
- data.local_transform.basis.rotate(data.rotation);
+ data.local_transform.basis.set_euler_scale(data.rotation, data.scale);
data.dirty &= ~DIRTY_LOCAL;
}
@@ -187,7 +186,9 @@ void Spatial::_notification(int p_what) {
if (data.gizmo.is_valid()) {
data.gizmo->create();
if (data.gizmo->can_draw()) {
- data.gizmo->redraw();
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
+ }
}
data.gizmo->transform();
}
@@ -285,6 +286,16 @@ Transform Spatial::get_global_transform() const {
return data.global_transform;
}
+#ifdef TOOLS_ENABLED
+Transform Spatial::get_global_gizmo_transform() const {
+ return get_global_transform();
+}
+
+Transform Spatial::get_local_gizmo_transform() const {
+ return get_transform();
+}
+#endif
+
Spatial *Spatial::get_parent_spatial() const {
return data.parent;
@@ -408,7 +419,9 @@ void Spatial::set_gizmo(const Ref<SpatialGizmo> &p_gizmo) {
data.gizmo->create();
if (data.gizmo->can_draw()) {
- data.gizmo->redraw();
+ if (is_visible_in_tree()) {
+ data.gizmo->redraw();
+ }
}
data.gizmo->transform();
}
@@ -427,10 +440,9 @@ Ref<SpatialGizmo> Spatial::get_gizmo() const {
#endif
}
-#ifdef TOOLS_ENABLED
-
void Spatial::_update_gizmo() {
+#ifdef TOOLS_ENABLED
if (!is_inside_world())
return;
data.gizmo_dirty = false;
@@ -442,8 +454,10 @@ void Spatial::_update_gizmo() {
data.gizmo->clear();
}
}
+#endif
}
+#ifdef TOOLS_ENABLED
void Spatial::set_disable_gizmo(bool p_enabled) {
data.gizmo_disabled = p_enabled;
@@ -555,30 +569,36 @@ bool Spatial::is_visible() const {
return data.visible;
}
-void Spatial::rotate(const Vector3 &p_normal, float p_radians) {
+void Spatial::rotate_object_local(const Vector3 &p_axis, float p_angle) {
+ Transform t = get_transform();
+ t.basis.rotate_local(p_axis, p_angle);
+ set_transform(t);
+}
+
+void Spatial::rotate(const Vector3 &p_axis, float p_angle) {
Transform t = get_transform();
- t.basis.rotate(p_normal, p_radians);
+ t.basis.rotate(p_axis, p_angle);
set_transform(t);
}
-void Spatial::rotate_x(float p_radians) {
+void Spatial::rotate_x(float p_angle) {
Transform t = get_transform();
- t.basis.rotate(Vector3(1, 0, 0), p_radians);
+ t.basis.rotate(Vector3(1, 0, 0), p_angle);
set_transform(t);
}
-void Spatial::rotate_y(float p_radians) {
+void Spatial::rotate_y(float p_angle) {
Transform t = get_transform();
- t.basis.rotate(Vector3(0, 1, 0), p_radians);
+ t.basis.rotate(Vector3(0, 1, 0), p_angle);
set_transform(t);
}
-void Spatial::rotate_z(float p_radians) {
+void Spatial::rotate_z(float p_angle) {
Transform t = get_transform();
- t.basis.rotate(Vector3(0, 0, 1), p_radians);
+ t.basis.rotate(Vector3(0, 0, 1), p_angle);
set_transform(t);
}
@@ -589,19 +609,45 @@ void Spatial::translate(const Vector3 &p_offset) {
set_transform(t);
}
+void Spatial::translate_object_local(const Vector3 &p_offset) {
+ Transform t = get_transform();
+
+ Transform s;
+ s.translate(p_offset);
+ set_transform(t * s);
+}
+
void Spatial::scale(const Vector3 &p_ratio) {
Transform t = get_transform();
t.basis.scale(p_ratio);
set_transform(t);
}
-void Spatial::global_rotate(const Vector3 &p_normal, float p_radians) {
- Basis rotation(p_normal, p_radians);
+void Spatial::scale_object_local(const Vector3 &p_scale) {
+ Transform t = get_transform();
+ t.basis.scale_local(p_scale);
+ set_transform(t);
+}
+
+void Spatial::global_rotate(const Vector3 &p_axis, float p_angle) {
+
+ Basis rotation(p_axis, p_angle);
Transform t = get_global_transform();
t.basis = rotation * t.basis;
set_global_transform(t);
}
+
+void Spatial::global_scale(const Vector3 &p_scale) {
+
+ Basis s;
+ s.set_scale(p_scale);
+
+ Transform t = get_global_transform();
+ t.basis = s * t.basis;
+ set_global_transform(t);
+}
+
void Spatial::global_translate(const Vector3 &p_offset) {
Transform t = get_global_transform();
t.origin += p_offset;
@@ -620,7 +666,7 @@ void Spatial::set_identity() {
set_transform(Transform());
}
-void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up_normal) {
+void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up) {
Transform lookat;
lookat.origin = get_global_transform().origin;
@@ -629,19 +675,19 @@ void Spatial::look_at(const Vector3 &p_target, const Vector3 &p_up_normal) {
ERR_FAIL();
}
- if (p_up_normal.cross(p_target - lookat.origin) == Vector3()) {
+ if (p_up.cross(p_target - lookat.origin) == Vector3()) {
ERR_EXPLAIN("Up vector and direction between node origin and target are aligned, look_at() failed");
ERR_FAIL();
}
- lookat = lookat.looking_at(p_target, p_up_normal);
+ lookat = lookat.looking_at(p_target, p_up);
set_global_transform(lookat);
}
-void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up_normal) {
+void Spatial::look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up) {
Transform lookat;
lookat.origin = p_pos;
- lookat = lookat.looking_at(p_target, p_up_normal);
+ lookat = lookat.looking_at(p_target, p_up);
set_global_transform(lookat);
}
@@ -677,9 +723,9 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_transform"), &Spatial::get_transform);
ClassDB::bind_method(D_METHOD("set_translation", "translation"), &Spatial::set_translation);
ClassDB::bind_method(D_METHOD("get_translation"), &Spatial::get_translation);
- ClassDB::bind_method(D_METHOD("set_rotation", "radians"), &Spatial::set_rotation);
+ ClassDB::bind_method(D_METHOD("set_rotation", "euler"), &Spatial::set_rotation);
ClassDB::bind_method(D_METHOD("get_rotation"), &Spatial::get_rotation);
- ClassDB::bind_method(D_METHOD("set_rotation_degrees", "degrees"), &Spatial::set_rotation_degrees);
+ ClassDB::bind_method(D_METHOD("set_rotation_degrees", "euler_degrees"), &Spatial::set_rotation_degrees);
ClassDB::bind_method(D_METHOD("get_rotation_degrees"), &Spatial::get_rotation_degrees);
ClassDB::bind_method(D_METHOD("set_scale", "scale"), &Spatial::set_scale);
ClassDB::bind_method(D_METHOD("get_scale"), &Spatial::get_scale);
@@ -691,9 +737,7 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_set_as_toplevel"), &Spatial::is_set_as_toplevel);
ClassDB::bind_method(D_METHOD("get_world"), &Spatial::get_world);
-#ifdef TOOLS_ENABLED
ClassDB::bind_method(D_METHOD("_update_gizmo"), &Spatial::_update_gizmo);
-#endif
ClassDB::bind_method(D_METHOD("update_gizmo"), &Spatial::update_gizmo);
ClassDB::bind_method(D_METHOD("set_gizmo", "gizmo"), &Spatial::set_gizmo);
@@ -711,22 +755,26 @@ void Spatial::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_notify_transform", "enable"), &Spatial::set_notify_transform);
ClassDB::bind_method(D_METHOD("is_transform_notification_enabled"), &Spatial::is_transform_notification_enabled);
- void rotate(const Vector3 &p_normal, float p_radians);
- void rotate_x(float p_radians);
- void rotate_y(float p_radians);
- void rotate_z(float p_radians);
+ void rotate(const Vector3 &p_axis, float p_angle);
+ void rotate_x(float p_angle);
+ void rotate_y(float p_angle);
+ void rotate_z(float p_angle);
void translate(const Vector3 &p_offset);
void scale(const Vector3 &p_ratio);
- void global_rotate(const Vector3 &p_normal, float p_radians);
+ void global_rotate(const Vector3 &p_axis, float p_angle);
void global_translate(const Vector3 &p_offset);
- ClassDB::bind_method(D_METHOD("rotate", "normal", "radians"), &Spatial::rotate);
- ClassDB::bind_method(D_METHOD("global_rotate", "normal", "radians"), &Spatial::global_rotate);
- ClassDB::bind_method(D_METHOD("rotate_x", "radians"), &Spatial::rotate_x);
- ClassDB::bind_method(D_METHOD("rotate_y", "radians"), &Spatial::rotate_y);
- ClassDB::bind_method(D_METHOD("rotate_z", "radians"), &Spatial::rotate_z);
- ClassDB::bind_method(D_METHOD("translate", "offset"), &Spatial::translate);
+ ClassDB::bind_method(D_METHOD("rotate", "axis", "angle"), &Spatial::rotate);
+ ClassDB::bind_method(D_METHOD("global_rotate", "axis", "angle"), &Spatial::global_rotate);
+ ClassDB::bind_method(D_METHOD("global_scale", "scale"), &Spatial::global_scale);
ClassDB::bind_method(D_METHOD("global_translate", "offset"), &Spatial::global_translate);
+ ClassDB::bind_method(D_METHOD("rotate_object_local", "axis", "angle"), &Spatial::rotate_object_local);
+ ClassDB::bind_method(D_METHOD("scale_object_local", "scale"), &Spatial::scale_object_local);
+ ClassDB::bind_method(D_METHOD("translate_object_local", "offset"), &Spatial::translate_object_local);
+ ClassDB::bind_method(D_METHOD("rotate_x", "angle"), &Spatial::rotate_x);
+ ClassDB::bind_method(D_METHOD("rotate_y", "angle"), &Spatial::rotate_y);
+ ClassDB::bind_method(D_METHOD("rotate_z", "angle"), &Spatial::rotate_z);
+ ClassDB::bind_method(D_METHOD("translate", "offset"), &Spatial::translate);
ClassDB::bind_method(D_METHOD("orthonormalize"), &Spatial::orthonormalize);
ClassDB::bind_method(D_METHOD("set_identity"), &Spatial::set_identity);
@@ -751,7 +799,7 @@ void Spatial::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_scale", "get_scale");
ADD_GROUP("Visibility", "");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
- //ADD_PROPERTY( PropertyInfo(Variant::TRANSFORM,"transform/local"), "set_transform", "get_transform") ;
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "gizmo", PROPERTY_HINT_RESOURCE_TYPE, "SpatialGizmo", 0), "set_gizmo", "get_gizmo");
ADD_SIGNAL(MethodInfo("visibility_changed"));
}
diff --git a/scene/3d/spatial.h b/scene/3d/spatial.h
index 8f53b4a066..a43bed3e4a 100644
--- a/scene/3d/spatial.h
+++ b/scene/3d/spatial.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPATIAL_H
#define SPATIAL_H
@@ -99,10 +100,8 @@ class Spatial : public Node {
#endif
} data;
-#ifdef TOOLS_ENABLED
void _update_gizmo();
-#endif
void _notify_dirty();
void _propagate_transform_changed(Spatial *p_origin);
@@ -146,6 +145,11 @@ public:
Transform get_transform() const;
Transform get_global_transform() const;
+#ifdef TOOLS_ENABLED
+ virtual Transform get_global_gizmo_transform() const;
+ virtual Transform get_local_gizmo_transform() const;
+#endif
+
void set_as_toplevel(bool p_enabled);
bool is_set_as_toplevel() const;
@@ -158,17 +162,23 @@ public:
Transform get_relative_transform(const Node *p_parent) const;
- void rotate(const Vector3 &p_normal, float p_radians);
- void rotate_x(float p_radians);
- void rotate_y(float p_radians);
- void rotate_z(float p_radians);
+ void rotate(const Vector3 &p_axis, float p_angle);
+ void rotate_x(float p_angle);
+ void rotate_y(float p_angle);
+ void rotate_z(float p_angle);
void translate(const Vector3 &p_offset);
void scale(const Vector3 &p_ratio);
- void global_rotate(const Vector3 &p_normal, float p_radians);
+
+ void rotate_object_local(const Vector3 &p_axis, float p_angle);
+ void scale_object_local(const Vector3 &p_scale);
+ void translate_object_local(const Vector3 &p_offset);
+
+ void global_rotate(const Vector3 &p_axis, float p_angle);
+ void global_scale(const Vector3 &p_scale);
void global_translate(const Vector3 &p_offset);
- void look_at(const Vector3 &p_target, const Vector3 &p_up_normal);
- void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up_normal);
+ void look_at(const Vector3 &p_target, const Vector3 &p_up);
+ void look_at_from_position(const Vector3 &p_pos, const Vector3 &p_target, const Vector3 &p_up);
Vector3 to_local(Vector3 p_global) const;
Vector3 to_global(Vector3 p_local) const;
diff --git a/scene/3d/spatial_velocity_tracker.cpp b/scene/3d/spatial_velocity_tracker.cpp
index 1c7423e645..c547e76e30 100644
--- a/scene/3d/spatial_velocity_tracker.cpp
+++ b/scene/3d/spatial_velocity_tracker.cpp
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* spatial_velocity_tracker.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "spatial_velocity_tracker.h"
#include "engine.h"
@@ -95,6 +125,8 @@ void SpatialVelocityTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_position", "position"), &SpatialVelocityTracker::update_position);
ClassDB::bind_method(D_METHOD("get_tracked_linear_velocity"), &SpatialVelocityTracker::get_tracked_linear_velocity);
ClassDB::bind_method(D_METHOD("reset", "position"), &SpatialVelocityTracker::reset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "track_physics_step"), "set_track_physics_step", "is_tracking_physics_step");
}
SpatialVelocityTracker::SpatialVelocityTracker() {
diff --git a/scene/3d/spatial_velocity_tracker.h b/scene/3d/spatial_velocity_tracker.h
index c4371ff1f7..a8278a4fb5 100644
--- a/scene/3d/spatial_velocity_tracker.h
+++ b/scene/3d/spatial_velocity_tracker.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* spatial_velocity_tracker.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 SPATIAL_VELOCITY_TRACKER_H
#define SPATIAL_VELOCITY_TRACKER_H
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 18ebc22c8b..232855c978 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "sprite_3d.h"
#include "core_string_names.h"
#include "scene/scene_string_names.h"
@@ -294,6 +295,7 @@ SpriteBase3D::SpriteBase3D() {
for (int i = 0; i < FLAG_MAX; i++)
flags[i] = i == FLAG_TRANSPARENT || i == FLAG_DOUBLE_SIDED;
+ alpha_cut = ALPHA_CUT_DISABLED;
axis = Vector3::AXIS_Z;
pixel_size = 0.01;
modulate = Color(1, 1, 1, 1);
diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h
index d18553a504..23e1d96b4b 100644
--- a/scene/3d/sprite_3d.h
+++ b/scene/3d/sprite_3d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPRITE_3D_H
#define SPRITE_3D_H
diff --git a/scene/3d/vehicle_body.cpp b/scene/3d/vehicle_body.cpp
index 2e3e179a7b..ee8d249981 100644
--- a/scene/3d/vehicle_body.cpp
+++ b/scene/3d/vehicle_body.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "vehicle_body.h"
#define ROLLING_INFLUENCE_FIX
@@ -374,7 +375,7 @@ void VehicleBody::_update_wheel(int p_idx, PhysicsDirectBodyState *s) {
Basis steeringMat(up, steering);
- Basis rotatingMat(right, -wheel.m_rotation);
+ Basis rotatingMat(right, wheel.m_rotation);
/*
if (p_idx==1)
@@ -523,7 +524,7 @@ void VehicleBody::_update_suspension(PhysicsDirectBodyState *s) {
//bilateral constraint between two dynamic objects
void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1,
- PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse) {
+ PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence) {
real_t normalLenSqr = normal.length_squared();
//ERR_FAIL_COND( normalLenSqr < real_t(1.1));
@@ -571,7 +572,7 @@ void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vec
b2invmass);
// FIXME: rel_vel assignment here is overwritten by the following assignment.
- // What seemes to be intented in the next next assignment is: rel_vel = normal.dot(rel_vel);
+ // What seemes to be intended in the next next assignment is: rel_vel = normal.dot(rel_vel);
// Investigate why.
real_t rel_vel = jac.getRelativeVelocity(
s->get_linear_velocity(),
@@ -581,8 +582,12 @@ void VehicleBody::_resolve_single_bilateral(PhysicsDirectBodyState *s, const Vec
rel_vel = normal.dot(vel);
- //TODO: move this into proper structure
- real_t contactDamping = real_t(0.4);
+ // !BAS! We had this set to 0.4, in bullet its 0.2
+ // real_t contactDamping = real_t(0.2);
+
+ // !BAS! But seeing we apply this frame by frame, makes more sense to me to make this time based
+ // keeping in mind our anti roll factor
+ real_t contactDamping = s->get_step() / p_rollInfluence;
#define ONLY_USE_LINEAR_MASS
#ifdef ONLY_USE_LINEAR_MASS
real_t massTerm = real_t(1.) / ((1.0 / mass) + b2invmass);
@@ -667,13 +672,8 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
m_forwardImpulse.resize(numWheel);
m_sideImpulse.resize(numWheel);
- int numWheelsOnGround = 0;
-
//collapse all those loops into one!
for (int i = 0; i < wheels.size(); i++) {
- VehicleWheel &wheelInfo = *wheels[i];
- if (wheelInfo.m_raycastInfo.m_isInContact)
- numWheelsOnGround++;
m_sideImpulse[i] = real_t(0.);
m_forwardImpulse[i] = real_t(0.);
}
@@ -703,7 +703,7 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
_resolve_single_bilateral(s, wheelInfo.m_raycastInfo.m_contactPointWS,
wheelInfo.m_raycastInfo.m_groundObject, wheelInfo.m_raycastInfo.m_contactPointWS,
- m_axle[i], m_sideImpulse[i]);
+ m_axle[i], m_sideImpulse[i], wheelInfo.m_rollInfluence);
m_sideImpulse[i] *= sideFrictionStiffness2;
}
@@ -815,26 +815,24 @@ void VehicleBody::_update_friction(PhysicsDirectBodyState *s) {
void VehicleBody::_direct_state_changed(Object *p_state) {
- PhysicsDirectBodyState *s = Object::cast_to<PhysicsDirectBodyState>(p_state);
+ RigidBody::_direct_state_changed(p_state);
- set_ignore_transform_notification(true);
- set_global_transform(s->get_transform());
- set_ignore_transform_notification(false);
+ state = Object::cast_to<PhysicsDirectBodyState>(p_state);
- float step = s->get_step();
+ float step = state->get_step();
for (int i = 0; i < wheels.size(); i++) {
- _update_wheel(i, s);
+ _update_wheel(i, state);
}
for (int i = 0; i < wheels.size(); i++) {
- _ray_cast(i, s);
- wheels[i]->set_transform(s->get_transform().inverse() * wheels[i]->m_worldTransform);
+ _ray_cast(i, state);
+ wheels[i]->set_transform(state->get_transform().inverse() * wheels[i]->m_worldTransform);
}
- _update_suspension(s);
+ _update_suspension(state);
for (int i = 0; i < wheels.size(); i++) {
@@ -847,21 +845,21 @@ void VehicleBody::_direct_state_changed(Object *p_state) {
suspensionForce = wheel.m_maxSuspensionForce;
}
Vector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step;
- Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - s->get_transform().origin;
+ Vector3 relpos = wheel.m_raycastInfo.m_contactPointWS - state->get_transform().origin;
- s->apply_impulse(relpos, impulse);
+ state->apply_impulse(relpos, impulse);
//getRigidBody()->applyImpulse(impulse, relpos);
}
- _update_friction(s);
+ _update_friction(state);
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel &wheel = *wheels[i];
- Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - s->get_transform().origin;
- Vector3 vel = s->get_linear_velocity() + (s->get_angular_velocity()).cross(relpos); // * mPos);
+ Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - state->get_transform().origin;
+ Vector3 vel = state->get_linear_velocity() + (state->get_angular_velocity()).cross(relpos); // * mPos);
if (wheel.m_raycastInfo.m_isInContact) {
- const Transform &chassisWorldTransform = s->get_transform();
+ const Transform &chassisWorldTransform = state->get_transform();
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
@@ -882,29 +880,8 @@ void VehicleBody::_direct_state_changed(Object *p_state) {
wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
}
- linear_velocity = s->get_linear_velocity();
-}
-
-void VehicleBody::set_mass(real_t p_mass) {
-
- mass = p_mass;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_MASS, mass);
-}
-
-real_t VehicleBody::get_mass() const {
-
- return mass;
-}
-void VehicleBody::set_friction(real_t p_friction) {
-
- friction = p_friction;
- PhysicsServer::get_singleton()->body_set_param(get_rid(), PhysicsServer::BODY_PARAM_FRICTION, friction);
-}
-
-real_t VehicleBody::get_friction() const {
-
- return friction;
+ state = NULL;
}
void VehicleBody::set_engine_force(float p_engine_force) {
@@ -935,18 +912,8 @@ float VehicleBody::get_steering() const {
return m_steeringValue;
}
-Vector3 VehicleBody::get_linear_velocity() const {
- return linear_velocity;
-}
-
void VehicleBody::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &VehicleBody::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &VehicleBody::get_mass);
-
- ClassDB::bind_method(D_METHOD("set_friction", "friction"), &VehicleBody::set_friction);
- ClassDB::bind_method(D_METHOD("get_friction"), &VehicleBody::get_friction);
-
ClassDB::bind_method(D_METHOD("set_engine_force", "engine_force"), &VehicleBody::set_engine_force);
ClassDB::bind_method(D_METHOD("get_engine_force"), &VehicleBody::get_engine_force);
@@ -956,21 +923,14 @@ void VehicleBody::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_steering", "steering"), &VehicleBody::set_steering);
ClassDB::bind_method(D_METHOD("get_steering"), &VehicleBody::get_steering);
- ClassDB::bind_method(D_METHOD("get_linear_velocity"), &VehicleBody::get_linear_velocity);
-
- ClassDB::bind_method(D_METHOD("_direct_state_changed"), &VehicleBody::_direct_state_changed);
-
ADD_GROUP("Motion", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01"), "set_engine_force", "get_engine_force");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "engine_force", PROPERTY_HINT_RANGE, "0.00,1024.0,0.01,or_greater"), "set_engine_force", "get_engine_force");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "brake", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_brake", "get_brake");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "steering", PROPERTY_HINT_RANGE, "-180,180.0,0.01"), "set_steering", "get_steering");
- ADD_GROUP("Mass", "");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "mass", PROPERTY_HINT_RANGE, "0.01,65536,0.01"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "friction", PROPERTY_HINT_RANGE, "0.01,1,0.01"), "set_friction", "get_friction");
}
VehicleBody::VehicleBody() :
- PhysicsBody(PhysicsServer::BODY_MODE_RIGID) {
+ RigidBody() {
m_pitchControl = 0;
m_currentVehicleSpeedKmHour = real_t(0.);
@@ -981,10 +941,11 @@ VehicleBody::VehicleBody() :
friction = 1;
+ state = NULL;
ccd = false;
exclude.insert(get_rid());
- PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
+ //PhysicsServer::get_singleton()->body_set_force_integration_callback(get_rid(), this, "_direct_state_changed");
set_mass(40);
}
diff --git a/scene/3d/vehicle_body.h b/scene/3d/vehicle_body.h
index c642eb61b8..1ac3693cc4 100644
--- a/scene/3d/vehicle_body.h
+++ b/scene/3d/vehicle_body.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VEHICLE_BODY_H
#define VEHICLE_BODY_H
@@ -138,20 +139,13 @@ public:
VehicleWheel();
};
-class VehicleBody : public PhysicsBody {
-
- GDCLASS(VehicleBody, PhysicsBody);
+class VehicleBody : public RigidBody {
- real_t mass;
- real_t friction;
+ GDCLASS(VehicleBody, RigidBody);
float engine_force;
float brake;
- Vector3 linear_velocity;
- Vector3 angular_velocity;
- bool ccd;
-
real_t m_pitchControl;
real_t m_steeringValue;
real_t m_currentVehicleSpeedKmHour;
@@ -174,7 +168,7 @@ class VehicleBody : public PhysicsBody {
btVehicleWheelContactPoint(PhysicsDirectBodyState *s, PhysicsBody *body1, const Vector3 &frictionPosWorld, const Vector3 &frictionDirectionWorld, real_t maxImpulse);
};
- void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse);
+ void _resolve_single_bilateral(PhysicsDirectBodyState *s, const Vector3 &pos1, PhysicsBody *body2, const Vector3 &pos2, const Vector3 &normal, real_t &impulse, real_t p_rollInfluence);
real_t _calc_rolling_friction(btVehicleWheelContactPoint &contactPoint);
void _update_friction(PhysicsDirectBodyState *s);
@@ -191,12 +185,6 @@ class VehicleBody : public PhysicsBody {
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_engine_force(float p_engine_force);
float get_engine_force() const;
@@ -206,8 +194,6 @@ public:
void set_steering(float p_steering);
float get_steering() const;
- Vector3 get_linear_velocity() const;
-
VehicleBody();
};
diff --git a/scene/3d/visibility_notifier.cpp b/scene/3d/visibility_notifier.cpp
index 47144c4b78..9d6e4941f3 100644
--- a/scene/3d/visibility_notifier.cpp
+++ b/scene/3d/visibility_notifier.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "visibility_notifier.h"
#include "engine.h"
@@ -169,7 +170,7 @@ void VisibilityEnabler::_find_nodes(Node *p_node) {
if (add) {
- p_node->connect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed", varray(p_node), CONNECT_ONESHOT);
+ p_node->connect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed", varray(p_node), CONNECT_ONESHOT);
nodes[p_node] = meta;
_change_node_state(p_node, false);
}
@@ -207,7 +208,7 @@ void VisibilityEnabler::_notification(int p_what) {
if (!visible)
_change_node_state(E->key(), true);
- E->key()->disconnect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed");
+ E->key()->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed");
}
nodes.clear();
@@ -239,7 +240,7 @@ void VisibilityEnabler::_node_removed(Node *p_node) {
if (!visible)
_change_node_state(p_node, true);
- p_node->disconnect(SceneStringNames::get_singleton()->tree_exited, this, "_node_removed");
+ p_node->disconnect(SceneStringNames::get_singleton()->tree_exiting, this, "_node_removed");
nodes.erase(p_node);
}
diff --git a/scene/3d/visibility_notifier.h b/scene/3d/visibility_notifier.h
index fc06cf5aec..b1985f4a0c 100644
--- a/scene/3d/visibility_notifier.h
+++ b/scene/3d/visibility_notifier.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VISIBILITY_NOTIFIER_H
#define VISIBILITY_NOTIFIER_H
diff --git a/scene/3d/visual_instance.cpp b/scene/3d/visual_instance.cpp
index b92e7ead04..00541a7d8a 100644
--- a/scene/3d/visual_instance.cpp
+++ b/scene/3d/visual_instance.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "visual_instance.h"
#include "scene/scene_string_names.h"
diff --git a/scene/3d/visual_instance.h b/scene/3d/visual_instance.h
index 5827f1e1fb..8458a343b2 100644
--- a/scene/3d/visual_instance.h
+++ b/scene/3d/visual_instance.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VISUAL_INSTANCE_H
#define VISUAL_INSTANCE_H
diff --git a/scene/3d/voxel_light_baker.cpp b/scene/3d/voxel_light_baker.cpp
index 98dc1590d8..670df5cc7f 100644
--- a/scene/3d/voxel_light_baker.cpp
+++ b/scene/3d/voxel_light_baker.cpp
@@ -1,5 +1,39 @@
+/*************************************************************************/
+/* voxel_light_baker.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 "voxel_light_baker.h"
#include "os/os.h"
+#include "os/threaded_array_processor.h"
+
+#include <stdlib.h>
+
#define FINDMINMAX(x0, x1, x2, min, max) \
min = max = x0; \
if (x1 < min) min = x1; \
@@ -183,14 +217,23 @@ static bool fast_tri_box_overlap(const Vector3 &boxcenter, const Vector3 boxhalf
return true; /* box and triangle overlaps */
}
-static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv) {
+static _FORCE_INLINE_ void get_uv_and_normal(const Vector3 &p_pos, const Vector3 *p_vtx, const Vector2 *p_uv, const Vector3 *p_normal, Vector2 &r_uv, Vector3 &r_normal) {
- if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2)
- return p_uv[0];
- if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2)
- return p_uv[1];
- if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2)
- return p_uv[2];
+ if (p_pos.distance_squared_to(p_vtx[0]) < CMP_EPSILON2) {
+ r_uv = p_uv[0];
+ r_normal = p_normal[0];
+ return;
+ }
+ if (p_pos.distance_squared_to(p_vtx[1]) < CMP_EPSILON2) {
+ r_uv = p_uv[1];
+ r_normal = p_normal[1];
+ return;
+ }
+ if (p_pos.distance_squared_to(p_vtx[2]) < CMP_EPSILON2) {
+ r_uv = p_uv[2];
+ r_normal = p_normal[2];
+ return;
+ }
Vector3 v0 = p_vtx[1] - p_vtx[0];
Vector3 v1 = p_vtx[2] - p_vtx[0];
@@ -202,16 +245,20 @@ static _FORCE_INLINE_ Vector2 get_uv(const Vector3 &p_pos, const Vector3 *p_vtx,
float d20 = v2.dot(v0);
float d21 = v2.dot(v1);
float denom = (d00 * d11 - d01 * d01);
- if (denom == 0)
- return p_uv[0];
+ if (denom == 0) {
+ r_uv = p_uv[0];
+ r_normal = p_normal[0];
+ return;
+ }
float v = (d11 * d20 - d01 * d21) / denom;
float w = (d00 * d21 - d01 * d20) / denom;
float u = 1.0f - v - w;
- return p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
+ r_uv = p_uv[0] * u + p_uv[1] * v + p_uv[2] * w;
+ r_normal = (p_normal[0] * u + p_normal[1] * v + p_normal[2] * w).normalized();
}
-void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
+void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb) {
if (p_level == cell_subdiv - 1) {
//plot the face by guessing it's albedo and emission value
@@ -289,7 +336,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
intersection = Face3(p_vtx[0], p_vtx[1], p_vtx[2]).get_closest_point_to(intersection);
- Vector2 uv = get_uv(intersection, p_vtx, p_uv);
+ Vector2 uv;
+ Vector3 lnormal;
+ get_uv_and_normal(intersection, p_vtx, p_uv, p_normal, uv, lnormal);
+ if (lnormal == Vector3()) //just in case normal as nor provided
+ lnormal = normal;
int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
@@ -304,7 +355,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
emission_accum.g += p_material.emission[ofs].g;
emission_accum.b += p_material.emission[ofs].b;
- normal_accum += normal;
+ normal_accum += lnormal;
alpha += 1.0;
}
@@ -316,7 +367,11 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
Face3 f(p_vtx[0], p_vtx[1], p_vtx[2]);
Vector3 inters = f.get_closest_point_to(p_aabb.position + p_aabb.size * 0.5);
- Vector2 uv = get_uv(inters, p_vtx, p_uv);
+ Vector3 lnormal;
+ Vector2 uv;
+ get_uv_and_normal(inters, p_vtx, p_uv, p_normal, uv, normal);
+ if (lnormal == Vector3()) //just in case normal as nor provided
+ lnormal = normal;
int uv_x = CLAMP(Math::fposmod(uv.x, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
int uv_y = CLAMP(Math::fposmod(uv.y, 1.0f) * bake_texture_size, 0, bake_texture_size - 1);
@@ -334,7 +389,7 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
emission_accum.g = p_material.emission[ofs].g * alpha;
emission_accum.b = p_material.emission[ofs].b * alpha;
- normal_accum *= alpha;
+ normal_accum = lnormal * alpha;
} else {
@@ -406,16 +461,16 @@ void VoxelLightBaker::_plot_face(int p_idx, int p_level, int p_x, int p_y, int p
}
}
- if (bake_cells[p_idx].childs[i] == CHILD_EMPTY) {
+ if (bake_cells[p_idx].children[i] == CHILD_EMPTY) {
//sub cell must be created
uint32_t child_idx = bake_cells.size();
- bake_cells[p_idx].childs[i] = child_idx;
+ bake_cells[p_idx].children[i] = child_idx;
bake_cells.resize(bake_cells.size() + 1);
bake_cells[child_idx].level = p_level + 1;
}
- _plot_face(bake_cells[p_idx].childs[i], p_level + 1, nx, ny, nz, p_vtx, p_uv, p_material, aabb);
+ _plot_face(bake_cells[p_idx].children[i], p_level + 1, nx, ny, nz, p_vtx, p_normal, p_uv, p_material, aabb);
}
}
}
@@ -539,9 +594,12 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
PoolVector<Vector3>::Read vr = vertices.read();
PoolVector<Vector2> uv = a[Mesh::ARRAY_TEX_UV];
PoolVector<Vector2>::Read uvr;
+ PoolVector<Vector3> normals = a[Mesh::ARRAY_NORMAL];
+ PoolVector<Vector3>::Read nr;
PoolVector<int> index = a[Mesh::ARRAY_INDEX];
bool read_uv = false;
+ bool read_normals = false;
if (uv.size()) {
@@ -549,6 +607,11 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
read_uv = true;
}
+ if (normals.size()) {
+ read_normals = true;
+ nr = normals.read();
+ }
+
if (index.size()) {
int facecount = index.size() / 3;
@@ -558,6 +621,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
Vector3 vtxs[3];
Vector2 uvs[3];
+ Vector3 normal[3];
for (int k = 0; k < 3; k++) {
vtxs[k] = p_xform.xform(vr[ir[j * 3 + k]]);
@@ -569,11 +633,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
}
}
+ if (read_normals) {
+ for (int k = 0; k < 3; k++) {
+ normal[k] = nr[ir[j * 3 + k]];
+ }
+ }
+
//test against original bounds
if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
continue;
//plot
- _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds);
+ _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
}
} else {
@@ -584,6 +654,7 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
Vector3 vtxs[3];
Vector2 uvs[3];
+ Vector3 normal[3];
for (int k = 0; k < 3; k++) {
vtxs[k] = p_xform.xform(vr[j * 3 + k]);
@@ -595,11 +666,17 @@ void VoxelLightBaker::plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, con
}
}
+ if (read_normals) {
+ for (int k = 0; k < 3; k++) {
+ normal[k] = nr[j * 3 + k];
+ }
+ }
+
//test against original bounds
if (!fast_tri_box_overlap(original_bounds.position + original_bounds.size * 0.5, original_bounds.size * 0.5, vtxs))
continue;
//plot face
- _plot_face(0, 0, 0, 0, 0, vtxs, uvs, material, po2_bounds);
+ _plot_face(0, 0, 0, 0, 0, vtxs, normal, uvs, material, po2_bounds);
}
}
}
@@ -623,7 +700,7 @@ void VoxelLightBaker::_init_light_plot(int p_idx, int p_level, int p_x, int p_y,
int half = (1 << (cell_subdiv - 1)) >> (p_level + 1);
for (int i = 0; i < 8; i++) {
- uint32_t child = bake_cells[p_idx].childs[i];
+ uint32_t child = bake_cells[p_idx].children[i];
if (child == CHILD_EMPTY)
continue;
@@ -732,7 +809,7 @@ uint32_t VoxelLightBaker::_find_cell_at_pos(const Cell *cells, int x, int y, int
ofs_z += half;
}
- cell = bc->childs[child];
+ cell = bc->children[child];
if (cell == CHILD_EMPTY)
return CHILD_EMPTY;
@@ -833,11 +910,13 @@ void VoxelLightBaker::plot_light_directional(const Vector3 &p_direction, const C
}
}
- for (int i = 0; i < 6; i++) {
- float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
- light->direct_accum[i][0] += light_energy.x * s;
- light->direct_accum[i][1] += light_energy.y * s;
- light->direct_accum[i][2] += light_energy.z * s;
+ if (p_direct) {
+ for (int i = 0; i < 6; i++) {
+ float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
+ light->direct_accum[i][0] += light_energy.x * s;
+ light->direct_accum[i][1] += light_energy.y * s;
+ light->direct_accum[i][2] += light_energy.z * s;
+ }
}
success_count++;
}
@@ -897,17 +976,7 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
float dt = CLAMP((d + distance_adv) / local_radius, 0, 1);
att *= powf(1.0 - dt, p_attenutation);
}
-#if 0
- if (light_cache.type == VS::LIGHT_SPOT) {
-
- float angle = Math::rad2deg(acos(light_axis.dot(spot_axis)));
- if (angle > light_cache.spot_angle)
- continue;
- float d = CLAMP(angle / light_cache.spot_angle, 1, 0);
- att *= powf(1.0 - d, light_cache.spot_attenuation);
- }
-#endif
clip_planes = 0;
for (int c = 0; c < 3; c++) {
@@ -972,11 +1041,13 @@ void VoxelLightBaker::plot_light_omni(const Vector3 &p_pos, const Color &p_color
}
}
- for (int i = 0; i < 6; i++) {
- float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
- light->direct_accum[i][0] += light_energy.x * s * att;
- light->direct_accum[i][1] += light_energy.y * s * att;
- light->direct_accum[i][2] += light_energy.z * s * att;
+ if (p_direct) {
+ for (int i = 0; i < 6; i++) {
+ float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
+ light->direct_accum[i][0] += light_energy.x * s * att;
+ light->direct_accum[i][1] += light_energy.y * s * att;
+ light->direct_accum[i][2] += light_energy.z * s * att;
+ }
}
}
@@ -1041,17 +1112,7 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
float dt = CLAMP((d + distance_adv) / local_radius, 0, 1);
att *= powf(1.0 - dt, p_attenutation);
}
-#if 0
- if (light_cache.type == VS::LIGHT_SPOT) {
-
- float angle = Math::rad2deg(acos(light_axis.dot(spot_axis)));
- if (angle > light_cache.spot_angle)
- continue;
- float d = CLAMP(angle / light_cache.spot_angle, 1, 0);
- att *= powf(1.0 - d, light_cache.spot_attenuation);
- }
-#endif
clip_planes = 0;
for (int c = 0; c < 3; c++) {
@@ -1115,11 +1176,13 @@ void VoxelLightBaker::plot_light_spot(const Vector3 &p_pos, const Vector3 &p_axi
}
}
- for (int i = 0; i < 6; i++) {
- float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
- light->direct_accum[i][0] += light_energy.x * s * att;
- light->direct_accum[i][1] += light_energy.y * s * att;
- light->direct_accum[i][2] += light_energy.z * s * att;
+ if (p_direct) {
+ for (int i = 0; i < 6; i++) {
+ float s = MAX(0.0, aniso_normal[i].dot(-light_axis)); //light depending on normal for direct
+ light->direct_accum[i][0] += light_energy.x * s * att;
+ light->direct_accum[i][1] += light_energy.y * s * att;
+ light->direct_accum[i][2] += light_energy.z * s * att;
+ }
}
}
@@ -1194,7 +1257,7 @@ void VoxelLightBaker::_fixup_plot(int p_idx, int p_level) {
for (int i = 0; i < 8; i++) {
- uint32_t child = bake_cells[p_idx].childs[i];
+ uint32_t child = bake_cells[p_idx].children[i];
if (child == CHILD_EMPTY)
continue;
@@ -1420,7 +1483,7 @@ void VoxelLightBaker::_sample_baked_octree_filtered_and_anisotropic(const Vector
ofs_z += half;
}
- cell = bc->childs[child];
+ cell = bc->children[child];
if (cell == CHILD_EMPTY)
break;
@@ -1614,6 +1677,16 @@ Vector3 VoxelLightBaker::_compute_pixel_light_at_pos(const Vector3 &p_pos, const
return accum;
}
+_ALWAYS_INLINE_ uint32_t xorshift32(uint32_t *state) {
+ /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
+ uint32_t x = *state;
+ x ^= x << 13;
+ x ^= x >> 17;
+ x ^= x << 5;
+ *state = x;
+ return x;
+}
+
Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal) {
int samples_per_quality[3] = { 48, 128, 512 };
@@ -1636,20 +1709,22 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
const Light *light = bake_light.ptr();
const Cell *cells = bake_cells.ptr();
+ uint32_t local_rng_state = rand(); //needs to be fixed again
+
for (int i = 0; i < samples; i++) {
- float random_angle1 = (((Math::rand() % 65535) / 65535.0) * 2.0 - 1.0) * spread;
+ float random_angle1 = (((xorshift32(&local_rng_state) % 65535) / 65535.0) * 2.0 - 1.0) * spread;
Vector3 axis(0, sin(random_angle1), cos(random_angle1));
- float random_angle2 = ((Math::rand() % 65535) / 65535.0) * Math_PI * 2.0;
+ float random_angle2 = ((xorshift32(&local_rng_state) % 65535) / 65535.0) * Math_PI * 2.0;
Basis rot(Vector3(0, 0, 1), random_angle2);
axis = rot.xform(axis);
Vector3 direction = normal_xform.xform(axis).normalized();
- Vector3 pos = p_pos + Vector3(0.5, 0.5, 0.5) + direction * bias;
-
Vector3 advance = direction * _get_normal_advance(direction);
+ Vector3 pos = p_pos /*+ Vector3(0.5, 0.5, 0.5)*/ + advance * bias;
+
uint32_t cell = CHILD_EMPTY;
while (cell == CHILD_EMPTY) {
@@ -1691,8 +1766,8 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
ofs_z += half;
}
- cell = bc->childs[child];
- if (cell == CHILD_EMPTY)
+ cell = bc->children[child];
+ if (unlikely(cell == CHILD_EMPTY))
break;
half >>= 1;
@@ -1701,22 +1776,45 @@ Vector3 VoxelLightBaker::_compute_ray_trace_at_pos(const Vector3 &p_pos, const V
pos += advance;
}
- if (cell != CHILD_EMPTY) {
+ if (unlikely(cell != CHILD_EMPTY)) {
for (int i = 0; i < 6; i++) {
//anisotropic read light
float amount = direction.dot(aniso_normal[i]);
- if (amount < 0)
- amount = 0;
+ if (amount <= 0)
+ continue;
accum.x += light[cell].accum[i][0] * amount;
accum.y += light[cell].accum[i][1] * amount;
accum.z += light[cell].accum[i][2] * amount;
}
+ accum.x += cells[cell].emission[0];
+ accum.y += cells[cell].emission[1];
+ accum.z += cells[cell].emission[2];
}
}
+ // Make sure we don't reset this thread's RNG state
+
return accum / samples;
}
+void VoxelLightBaker::_lightmap_bake_point(uint32_t p_x, LightMap *p_line) {
+
+ LightMap *pixel = &p_line[p_x];
+ if (pixel->pos == Vector3())
+ return;
+ //print_line("pos: " + pixel->pos + " normal " + pixel->normal);
+ switch (bake_mode) {
+ case BAKE_MODE_CONE_TRACE: {
+ pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy;
+ } break;
+ case BAKE_MODE_RAY_TRACE: {
+ pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy;
+ } break;
+ // pixel->light = Vector3(1, 1, 1);
+ //}
+ }
+}
+
Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh, LightMapData &r_lightmap, bool (*p_bake_time_func)(void *, float, float), void *p_bake_time_ud) {
//transfer light information to a lightmap
@@ -1760,6 +1858,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
Vector3 vertex[3];
Vector3 normal[3];
Vector2 uv[3];
+
for (int j = 0; j < 3; j++) {
int idx = ic ? ir[i * 3 + j] : i * 3 + j;
vertex[j] = xform.xform(vr[idx]);
@@ -1770,39 +1869,18 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
_plot_triangle(uv, vertex, normal, lightmap.ptrw(), width, height);
}
}
- //step 3 perform voxel cone trace on lightmap pixels
+ //step 3 perform voxel cone trace on lightmap pixels
{
LightMap *lightmap_ptr = lightmap.ptrw();
uint64_t begin_time = OS::get_singleton()->get_ticks_usec();
volatile int lines = 0;
+ // make sure our OS-level rng is seeded
+
for (int i = 0; i < height; i++) {
- //print_line("bake line " + itos(i) + " / " + itos(height));
-#ifdef _OPENMP
-#pragma omp parallel for
-#endif
- for (int j = 0; j < width; j++) {
-
- //if (i == 125 && j == 280) {
-
- LightMap *pixel = &lightmap_ptr[i * width + j];
- if (pixel->pos == Vector3())
- continue; //unused, skipe
-
- //print_line("pos: " + pixel->pos + " normal " + pixel->normal);
- switch (bake_mode) {
- case BAKE_MODE_CONE_TRACE: {
- pixel->light = _compute_pixel_light_at_pos(pixel->pos, pixel->normal) * energy;
- } break;
- case BAKE_MODE_RAY_TRACE: {
- pixel->light = _compute_ray_trace_at_pos(pixel->pos, pixel->normal) * energy;
- } break;
- // pixel->light = Vector3(1, 1, 1);
- //}
- }
- }
+ thread_process_array(width, this, &VoxelLightBaker::_lightmap_bake_point, &lightmap_ptr[i * width]);
lines = MAX(lines, i); //for multithread
if (p_bake_time_func) {
@@ -1850,7 +1928,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (lightmap_ptr[i * width + j].normal == Vector3())
- continue; //empty, dont write over it anyway
+ continue; //empty, don't write over it anyway
float gauss_sum = gauss_kernel[0];
Vector3 accum = lightmap_ptr[i * width + j].pos * gauss_kernel[0];
for (int k = 1; k < 4; k++) {
@@ -1878,12 +1956,14 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
LightMap *lightmap_ptr = lightmap.ptrw();
const Cell *cells = bake_cells.ptr();
const Light *light = bake_light.ptr();
-
+#ifdef _OPENMP
+#pragma omp parallel
+#endif
for (int i = 0; i < height; i++) {
//print_line("bake line " + itos(i) + " / " + itos(height));
#ifdef _OPENMP
-#pragma omp parallel for
+#pragma omp parallel for schedule(dynamic, 1)
#endif
for (int j = 0; j < width; j++) {
@@ -2002,6 +2082,7 @@ Error VoxelLightBaker::make_lightmap(const Transform &p_xform, Ref<Mesh> &p_mesh
}
}
+// Enable for debugging
#if 0
{
PoolVector<uint8_t> img;
@@ -2110,7 +2191,7 @@ PoolVector<int> VoxelLightBaker::create_gi_probe_data() {
for (int i = 0; i < bake_cells.size(); i++) {
for (int j = 0; j < 8; j++) {
- w32[ofs++] = bake_cells[i].childs[j];
+ w32[ofs++] = bake_cells[i].children[j];
}
{ //albedo
@@ -2194,7 +2275,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re
for (int i = 0; i < 8; i++) {
- uint32_t child = bake_cells[p_idx].childs[i];
+ uint32_t child = bake_cells[p_idx].children[i];
if (child == CHILD_EMPTY || child >= max_original_cells)
continue;
@@ -2209,7 +2290,7 @@ void VoxelLightBaker::_debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Re
if (i & 4)
aabb.position.z += aabb.size.z;
- _debug_mesh(bake_cells[p_idx].childs[i], p_level + 1, aabb, p_multimesh, idx, p_mode);
+ _debug_mesh(bake_cells[p_idx].children[i], p_level + 1, aabb, p_multimesh, idx, p_mode);
}
}
}
@@ -2235,13 +2316,10 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
PoolVector<Vector3> vertices;
PoolVector<Color> colors;
-
- int vtx_idx = 0;
#define ADD_VTX(m_idx) \
; \
vertices.push_back(face_points[m_idx]); \
- colors.push_back(Color(1, 1, 1, 1)); \
- vtx_idx++;
+ colors.push_back(Color(1, 1, 1, 1));
for (int i = 0; i < 6; i++) {
@@ -2257,9 +2335,9 @@ Ref<MultiMesh> VoxelLightBaker::create_debug_multimesh(DebugMode p_mode) {
for (int k = 0; k < 3; k++) {
if (i < 3)
- face_points[j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
+ face_points[j][(i + k) % 3] = v[k];
else
- face_points[3 - j][(i + k) % 3] = v[k] * (i >= 3 ? -1 : 1);
+ face_points[3 - j][(i + k) % 3] = -v[k];
}
}
@@ -2342,7 +2420,7 @@ PoolVector<uint8_t> VoxelLightBaker::create_capture_octree(int p_subdiv) {
}
for (int j = 0; j < 8; j++) {
- uint32_t child = bake_cells[demap[i]].childs[j];
+ uint32_t child = bake_cells[demap[i]].children[j];
octree[i].children[j] = child == CHILD_EMPTY ? CHILD_EMPTY : remap[child];
}
}
diff --git a/scene/3d/voxel_light_baker.h b/scene/3d/voxel_light_baker.h
index 6dee2ee69b..6a1f1253a3 100644
--- a/scene/3d/voxel_light_baker.h
+++ b/scene/3d/voxel_light_baker.h
@@ -1,3 +1,33 @@
+/*************************************************************************/
+/* voxel_light_baker.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* 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 VOXEL_LIGHT_BAKER_H
#define VOXEL_LIGHT_BAKER_H
@@ -30,7 +60,7 @@ private:
struct Cell {
- uint32_t childs[8];
+ uint32_t children[8];
float albedo[3]; //albedo in RGB24
float emission[3]; //accumulated light in 16:16 fixed point (needs to be integer for moving lights fast)
float normal[3];
@@ -40,7 +70,7 @@ private:
Cell() {
for (int i = 0; i < 8; i++) {
- childs[i] = CHILD_EMPTY;
+ children[i] = CHILD_EMPTY;
}
for (int i = 0; i < 3; i++) {
@@ -99,7 +129,8 @@ private:
Vector<Color> _get_bake_texture(Ref<Image> p_image, const Color &p_color_mul, const Color &p_color_add);
MaterialCache _get_material_cache(Ref<Material> p_material);
- void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb);
+
+ void _plot_face(int p_idx, int p_level, int p_x, int p_y, int p_z, const Vector3 *p_vtx, const Vector3 *p_normal, const Vector2 *p_uv, const MaterialCache &p_material, const AABB &p_aabb);
void _fixup_plot(int p_idx, int p_level);
void _debug_mesh(int p_idx, int p_level, const AABB &p_aabb, Ref<MultiMesh> &p_multimesh, int &idx, DebugMode p_mode);
void _check_init_light();
@@ -119,6 +150,8 @@ private:
_FORCE_INLINE_ Vector3 _compute_pixel_light_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
_FORCE_INLINE_ Vector3 _compute_ray_trace_at_pos(const Vector3 &p_pos, const Vector3 &p_normal);
+ void _lightmap_bake_point(uint32_t p_x, LightMap *p_line);
+
public:
void begin_bake(int p_subdiv, const AABB &p_bounds);
void plot_mesh(const Transform &p_xform, Ref<Mesh> &p_mesh, const Vector<Ref<Material> > &p_materials, const Ref<Material> &p_override_material);
diff --git a/scene/animation/animation_cache.cpp b/scene/animation/animation_cache.cpp
index fbe2593362..949a0be3bc 100644
--- a/scene/animation/animation_cache.cpp
+++ b/scene/animation/animation_cache.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "animation_cache.h"
void AnimationCache::_node_exit_tree(Node *p_node) {
@@ -55,7 +56,7 @@ void AnimationCache::_clear_cache() {
while (connected_nodes.size()) {
- connected_nodes.front()->get()->disconnect("tree_exited", this, "_node_exit_tree");
+ connected_nodes.front()->get()->disconnect("tree_exiting", this, "_node_exit_tree");
connected_nodes.erase(connected_nodes.front());
}
path_cache.clear();
@@ -180,7 +181,7 @@ void AnimationCache::_update_cache() {
if (!connected_nodes.has(path.node)) {
connected_nodes.insert(path.node);
- path.node->connect("tree_exited", this, "_node_exit_tree", Node::make_binds(path.node), CONNECT_ONESHOT);
+ path.node->connect("tree_exiting", this, "_node_exit_tree", Node::make_binds(path.node), CONNECT_ONESHOT);
}
}
diff --git a/scene/animation/animation_cache.h b/scene/animation/animation_cache.h
index 481de59730..cf28236376 100644
--- a/scene/animation/animation_cache.h
+++ b/scene/animation/animation_cache.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ANIMATION_CACHE_H
#define ANIMATION_CACHE_H
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 5e776c5a1a..a0e0137863 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "animation_player.h"
#include "engine.h"
@@ -48,24 +49,15 @@ bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
- if (p_name == SceneStringNames::get_singleton()->playback_speed || p_name == SceneStringNames::get_singleton()->speed) { //bw compatibility
- set_speed_scale(p_value);
-
- } else if (p_name == SceneStringNames::get_singleton()->playback_active) {
- set_active(p_value);
- } else if (name.begins_with("playback/play")) {
+ if (name.begins_with("playback/play")) { // bw compatibility
- String which = p_value;
+ set_current_animation(p_value);
- if (which == "[stop]")
- stop();
- else
- play(which);
} else if (name.begins_with("anims/")) {
String which = name.get_slicec('/', 1);
-
add_animation(which, p_value);
+
} else if (name.begins_with("next/")) {
String which = name.get_slicec('/', 1);
@@ -86,9 +78,6 @@ bool AnimationPlayer::_set(const StringName &p_name, const Variant &p_value) {
set_blend_time(from, to, time);
}
- } else if (p_name == SceneStringNames::get_singleton()->autoplay) {
- autoplay = p_value;
-
} else
return false;
@@ -99,24 +88,15 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
- if (name == "playback/speed") { //bw compatibility
+ if (name == "playback/play") { // bw compatibility
- r_ret = speed_scale;
- } else if (name == "playback/active") {
-
- r_ret = is_active();
- } else if (name == "playback/play") {
-
- if (is_active() && is_playing())
- r_ret = playback.assigned;
- else
- r_ret = "[stop]";
+ r_ret = get_current_animation();
} else if (name.begins_with("anims/")) {
String which = name.get_slicec('/', 1);
-
r_ret = get_animation(which).get_ref_ptr();
+
} else if (name.begins_with("next/")) {
String which = name.get_slicec('/', 1);
@@ -140,27 +120,43 @@ bool AnimationPlayer::_get(const StringName &p_name, Variant &r_ret) const {
}
r_ret = array;
- } else if (name == "autoplay") {
- r_ret = autoplay;
-
} else
return false;
return true;
}
-void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
+void AnimationPlayer::_validate_property(PropertyInfo &property) const {
- List<String> names;
+ if (property.name == "current_animation") {
+ List<String> names;
+
+ for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
+ names.push_back(E->key());
+ }
+ names.sort();
+ names.push_front("[stop]");
+ String hint;
+ for (List<String>::Element *E = names.front(); E; E = E->next()) {
+
+ if (E != names.front())
+ hint += ",";
+ hint += E->get();
+ }
+
+ property.hint_string = hint;
+ }
+}
+
+void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
List<PropertyInfo> anim_names;
for (Map<StringName, AnimationData>::Element *E = animation_set.front(); E; E = E->next()) {
- anim_names.push_back(PropertyInfo(Variant::OBJECT, "anims/" + String(E->key()), PROPERTY_HINT_RESOURCE_TYPE, "Animation", PROPERTY_USAGE_NOEDITOR));
+ anim_names.push_back(PropertyInfo(Variant::OBJECT, "anims/" + String(E->key()), PROPERTY_HINT_RESOURCE_TYPE, "Animation", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
if (E->get().next != StringName())
- anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- names.push_back(E->key());
+ anim_names.push_back(PropertyInfo(Variant::STRING, "next/" + String(E->key()), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
anim_names.sort();
@@ -169,24 +165,7 @@ void AnimationPlayer::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(E->get());
}
- {
- names.sort();
- names.push_front("[stop]");
- String hint;
- for (List<String>::Element *E = names.front(); E; E = E->next()) {
-
- if (E != names.front())
- hint += ",";
- hint += E->get();
- }
-
- p_list->push_back(PropertyInfo(Variant::STRING, "playback/play", PROPERTY_HINT_ENUM, hint, PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ANIMATE_AS_TRIGGER));
- p_list->push_back(PropertyInfo(Variant::BOOL, "playback/active", PROPERTY_HINT_NONE, ""));
- p_list->push_back(PropertyInfo(Variant::REAL, "playback/speed", PROPERTY_HINT_RANGE, "-64,64,0.01"));
- }
-
- p_list->push_back(PropertyInfo(Variant::ARRAY, "blend_times", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::STRING, "autoplay", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "blend_times", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
void AnimationPlayer::advance(float p_time) {
@@ -203,8 +182,8 @@ void AnimationPlayer::_notification(int p_what) {
if (!processing) {
//make sure that a previous process state was not saved
//only process if "processing" is set
- set_physics_process(false);
- set_process(false);
+ set_physics_process_internal(false);
+ set_process_internal(false);
}
//_set_process(false);
clear_caches();
@@ -267,16 +246,17 @@ void AnimationPlayer::_ensure_node_caches(AnimationData *p_anim) {
if (a->track_get_path(i).get_subname_count() == 1 && Object::cast_to<Skeleton>(child)) {
- bone_idx = Object::cast_to<Skeleton>(child)->find_bone(a->track_get_path(i).get_subname(0));
- if (bone_idx == -1) {
+ Skeleton *sk = Object::cast_to<Skeleton>(child);
+ bone_idx = sk->find_bone(a->track_get_path(i).get_subname(0));
+ if (bone_idx == -1 || sk->is_bone_ignore_animation(bone_idx)) {
continue;
}
}
{
- if (!child->is_connected("tree_exited", this, "_node_removed"))
- child->connect("tree_exited", this, "_node_removed", make_binds(child), CONNECT_ONESHOT);
+ if (!child->is_connected("tree_exiting", this, "_node_removed"))
+ child->connect("tree_exiting", this, "_node_removed", make_binds(child), CONNECT_ONESHOT);
}
TrackNodeCacheKey key;
@@ -527,7 +507,6 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, float
void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, float p_blend) {
float delta = p_delta * speed_scale * cd.speed_scale;
- bool backwards = delta < 0;
float next_pos = cd.pos + delta;
float len = cd.from->animation->get_length();
@@ -545,14 +524,18 @@ void AnimationPlayer::_animation_process_data(PlaybackData &cd, float p_delta, f
if (&cd == &playback.current) {
+ bool backwards = delta < 0;
+
if (!backwards && cd.pos <= len && next_pos == len /*&& playback.blend.empty()*/) {
//playback finished
- end_notify = true;
+ end_reached = true;
+ end_notify = cd.pos < len; // Notify only if not already at the end
}
if (backwards && cd.pos >= 0 && next_pos == 0 /*&& playback.blend.empty()*/) {
//playback finished
- end_notify = true;
+ end_reached = true;
+ end_notify = cd.pos > 0; // Notify only if not already at the beginning
}
}
@@ -598,20 +581,16 @@ void AnimationPlayer::_animation_process2(float p_delta) {
}
void AnimationPlayer::_animation_update_transforms() {
+ {
+ Transform t;
+ for (int i = 0; i < cache_update_size; i++) {
- for (int i = 0; i < cache_update_size; i++) {
-
- TrackNodeCache *nc = cache_update[i];
-
- ERR_CONTINUE(nc->accum_pass != accum_pass);
+ TrackNodeCache *nc = cache_update[i];
- if (nc->spatial) {
+ ERR_CONTINUE(nc->accum_pass != accum_pass);
- Transform t;
t.origin = nc->loc_accum;
- t.basis = nc->rot_accum;
- t.basis.scale(nc->scale_accum);
-
+ t.basis.set_quat_scale(nc->rot_accum, nc->scale_accum);
if (nc->skeleton && nc->bone_idx >= 0) {
nc->skeleton->set_bone_pose(nc->bone_idx, t);
@@ -679,24 +658,26 @@ void AnimationPlayer::_animation_process(float p_delta) {
if (playback.current.from) {
+ end_reached = false;
end_notify = false;
_animation_process2(p_delta);
_animation_update_transforms();
- if (end_notify) {
+ if (end_reached) {
if (queued.size()) {
String old = playback.assigned;
play(queued.front()->get());
String new_name = playback.assigned;
queued.pop_front();
- end_notify = false;
- emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);
+ if (end_notify)
+ emit_signal(SceneStringNames::get_singleton()->animation_changed, old, new_name);
} else {
//stop();
playing = false;
_set_process(false);
- end_notify = false;
- emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned);
+ if (end_notify)
+ emit_signal(SceneStringNames::get_singleton()->animation_finished, playback.assigned);
}
+ end_reached = false;
}
} else {
@@ -954,7 +935,7 @@ void AnimationPlayer::play(const StringName &p_name, float p_custom_blend, float
c.current.speed_scale = p_custom_scale;
c.assigned = p_name;
- if (!end_notify)
+ if (!end_reached)
queued.clear();
_set_process(true); // always process when starting an animation
playing = true;
@@ -985,10 +966,27 @@ bool AnimationPlayer::is_playing() const {
};
return true;
- */
+ */
}
+
void AnimationPlayer::set_current_animation(const String &p_anim) {
+ if (p_anim == "[stop]" || p_anim == "") {
+ stop();
+ } else if (!is_playing() || playback.assigned != p_anim) {
+ play(p_anim);
+ } else {
+ // Same animation, do not replay from start
+ }
+}
+
+String AnimationPlayer::get_current_animation() const {
+
+ return (is_playing() ? playback.assigned : "");
+}
+
+void AnimationPlayer::set_assigned_animation(const String &p_anim) {
+
if (is_playing()) {
play(p_anim);
} else {
@@ -999,9 +997,9 @@ void AnimationPlayer::set_current_animation(const String &p_anim) {
}
}
-String AnimationPlayer::get_current_animation() const {
+String AnimationPlayer::get_assigned_animation() const {
- return (playback.assigned);
+ return playback.assigned;
}
void AnimationPlayer::stop(bool p_reset) {
@@ -1010,6 +1008,7 @@ void AnimationPlayer::stop(bool p_reset) {
c.blend.clear();
if (p_reset) {
c.current.from = NULL;
+ c.current.speed_scale = 1;
}
_set_process(false);
queued.clear();
@@ -1024,12 +1023,21 @@ float AnimationPlayer::get_speed_scale() const {
return speed_scale;
}
+float AnimationPlayer::get_playing_speed() const {
+
+ if (!playing) {
+ return 0;
+ }
+ return speed_scale * playback.current.speed_scale;
+}
void AnimationPlayer::seek(float p_time, bool p_update) {
if (!playback.current.from) {
- if (playback.assigned)
- set_current_animation(playback.assigned);
+ if (playback.assigned) {
+ ERR_FAIL_COND(!animation_set.has(playback.assigned));
+ playback.current.from = &animation_set[playback.assigned];
+ }
ERR_FAIL_COND(!playback.current.from);
}
@@ -1042,8 +1050,10 @@ void AnimationPlayer::seek(float p_time, bool p_update) {
void AnimationPlayer::seek_delta(float p_time, float p_delta) {
if (!playback.current.from) {
- if (playback.assigned)
- set_current_animation(playback.assigned);
+ if (playback.assigned) {
+ ERR_FAIL_COND(!animation_set.has(playback.assigned));
+ playback.current.from = &animation_set[playback.assigned];
+ }
ERR_FAIL_COND(!playback.current.from);
}
@@ -1198,7 +1208,7 @@ NodePath AnimationPlayer::get_root() const {
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") {
+ if (p_function == "play" || p_function == "play_backwards" || 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()) {
@@ -1301,6 +1311,8 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation);
ClassDB::bind_method(D_METHOD("get_current_animation"), &AnimationPlayer::get_current_animation);
+ ClassDB::bind_method(D_METHOD("set_assigned_animation", "anim"), &AnimationPlayer::set_assigned_animation);
+ ClassDB::bind_method(D_METHOD("get_assigned_animation"), &AnimationPlayer::get_assigned_animation);
ClassDB::bind_method(D_METHOD("queue", "name"), &AnimationPlayer::queue);
ClassDB::bind_method(D_METHOD("clear_queue"), &AnimationPlayer::clear_queue);
@@ -1309,6 +1321,7 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_speed_scale", "speed"), &AnimationPlayer::set_speed_scale);
ClassDB::bind_method(D_METHOD("get_speed_scale"), &AnimationPlayer::get_speed_scale);
+ ClassDB::bind_method(D_METHOD("get_playing_speed"), &AnimationPlayer::get_playing_speed);
ClassDB::bind_method(D_METHOD("set_autoplay", "name"), &AnimationPlayer::set_autoplay);
ClassDB::bind_method(D_METHOD("get_autoplay"), &AnimationPlayer::get_autoplay);
@@ -1329,14 +1342,22 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("seek", "seconds", "update"), &AnimationPlayer::seek, DEFVAL(false));
ClassDB::bind_method(D_METHOD("advance", "delta"), &AnimationPlayer::advance);
+ ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_animation", PROPERTY_HINT_ENUM, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ANIMATE_AS_TRIGGER), "set_current_animation", "get_current_animation");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "assigned_animation", PROPERTY_HINT_NONE, "", 0), "set_assigned_animation", "get_assigned_animation");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "autoplay", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_autoplay", "get_autoplay");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "current_animation_length", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_length");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "current_animation_position", PROPERTY_HINT_NONE, "", 0), "", "get_current_animation_position");
+
ADD_GROUP("Playback Options", "playback_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_animation_process_mode", "get_animation_process_mode");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_default_blend_time", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_default_blend_time", "get_default_blend_time");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "root_node"), "set_root", "get_root");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playback_active", PROPERTY_HINT_NONE, "", 0), "set_active", "is_active");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
- ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("animation_finished", PropertyInfo(Variant::STRING, "anim_name")));
ADD_SIGNAL(MethodInfo("animation_changed", PropertyInfo(Variant::STRING, "old_name"), PropertyInfo(Variant::STRING, "new_name")));
- ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("animation_started", PropertyInfo(Variant::STRING, "anim_name")));
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(ANIMATION_PROCESS_IDLE);
@@ -1348,6 +1369,7 @@ AnimationPlayer::AnimationPlayer() {
cache_update_size = 0;
cache_update_prop_size = 0;
speed_scale = 1;
+ end_reached = false;
end_notify = false;
animation_process_mode = ANIMATION_PROCESS_IDLE;
processing = false;
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index e39afcf199..af2022ddac 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ANIMATION_PLAYER_H
#define ANIMATION_PLAYER_H
@@ -205,6 +206,7 @@ private:
List<StringName> queued;
+ bool end_reached;
bool end_notify;
String autoplay;
@@ -249,6 +251,7 @@ private:
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
+ virtual void _validate_property(PropertyInfo &property) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
void _notification(int p_what);
@@ -281,6 +284,8 @@ public:
bool is_playing() const;
String get_current_animation() const;
void set_current_animation(const String &p_anim);
+ String get_assigned_animation() const;
+ void set_assigned_animation(const String &p_anim);
void stop_all();
void set_active(bool p_active);
bool is_active() const;
@@ -288,6 +293,7 @@ public:
void set_speed_scale(float p_speed);
float get_speed_scale() const;
+ float get_playing_speed() const;
void set_autoplay(const String &p_name);
String get_autoplay() const;
diff --git a/scene/animation/animation_tree_player.cpp b/scene/animation/animation_tree_player.cpp
index 32f82fe6b8..ce5b372d72 100644
--- a/scene/animation/animation_tree_player.cpp
+++ b/scene/animation/animation_tree_player.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "animation_tree_player.h"
#include "animation_player.h"
@@ -386,8 +387,6 @@ bool AnimationTreePlayer::_get(const StringName &p_name, Variant &r_ret) const {
void AnimationTreePlayer::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "base_path"));
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "master_player"));
p_list->push_back(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_NETWORK));
}
@@ -558,7 +557,7 @@ float AnimationTreePlayer::_process_node(const StringName &p_node, AnimationNode
return _process_node(osn->inputs[0].node, r_prev_anim, p_time, p_seek, p_fallback_weight, p_weights);
}
- float os_seek = p_seek;
+ bool os_seek = p_seek;
if (p_seek)
osn->time = p_time;
@@ -814,7 +813,11 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
t.value = t.object->get_indexed(t.subpath);
t.value.zero();
- t.skip = false;
+ if (t.skeleton) {
+ t.skip = t.skeleton->is_bone_ignore_animation(t.bone_idx);
+ } else {
+ t.skip = false;
+ }
}
/* STEP 2 PROCESS ANIMATIONS */
@@ -896,13 +899,12 @@ void AnimationTreePlayer::_process_animation(float p_delta) {
}
Transform xform;
- xform.basis = t.rot;
xform.origin = t.loc;
t.scale.x += 1.0;
t.scale.y += 1.0;
t.scale.z += 1.0;
- xform.basis.scale(t.scale);
+ xform.basis.set_quat_scale(t.rot, t.scale);
if (t.bone_idx >= 0) {
if (t.skeleton)
@@ -1140,6 +1142,9 @@ void AnimationTreePlayer::transition_node_set_input_count(const StringName &p_no
n->inputs.resize(p_inputs);
n->input_data.resize(p_inputs);
+
+ _clear_cycle_test();
+
last_error = _cycle_test(out_name);
}
void AnimationTreePlayer::transition_node_set_input_auto_advance(const StringName &p_node, int p_input, bool p_auto_advance) {
@@ -1360,6 +1365,8 @@ void AnimationTreePlayer::remove_node(const StringName &p_node) {
node_map.erase(p_node);
+ _clear_cycle_test();
+
// compute last error again, just in case
last_error = _cycle_test(out_name);
dirty_caches = true;
@@ -1387,6 +1394,14 @@ AnimationTreePlayer::ConnectError AnimationTreePlayer::_cycle_test(const StringN
return CONNECT_OK;
}
+// Use this function to not alter next complete _cycle_test().
+void AnimationTreePlayer::_clear_cycle_test() {
+ for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) {
+ NodeBase *nb = E->get();
+ nb->cycletest = false;
+ }
+}
+
Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const StringName &p_dst_node, int p_dst_input) {
ERR_FAIL_COND_V(!node_map.has(p_src_node), ERR_INVALID_PARAMETER);
@@ -1411,11 +1426,7 @@ Error AnimationTreePlayer::connect_nodes(const StringName &p_src_node, const Str
dst->inputs[p_dst_input].node = p_src_node;
- for (Map<StringName, NodeBase *>::Element *E = node_map.front(); E; E = E->next()) {
-
- NodeBase *nb = E->get();
- nb->cycletest = false;
- }
+ _clear_cycle_test();
last_error = _cycle_test(out_name);
if (last_error) {
diff --git a/scene/animation/animation_tree_player.h b/scene/animation/animation_tree_player.h
index c49b0c4d1b..09d6f6fcb4 100644
--- a/scene/animation/animation_tree_player.h
+++ b/scene/animation/animation_tree_player.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ANIMATION_TREE_PLAYER_H
#define ANIMATION_TREE_PLAYER_H
@@ -317,6 +318,7 @@ private:
bool reset_request;
ConnectError _cycle_test(const StringName &p_at_node);
+ void _clear_cycle_test();
Track *_find_track(const NodePath &p_path);
void _recompute_caches();
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 151632a0cb..49013b160a 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tween.h"
#include "method_bind_ext.gen.inc"
@@ -218,11 +219,13 @@ void Tween::_bind_methods() {
ClassDB::bind_method(D_METHOD("targeting_property", "object", "property", "initial", "initial_val", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::targeting_property, DEFVAL(0));
ClassDB::bind_method(D_METHOD("targeting_method", "object", "method", "initial", "initial_method", "final_val", "duration", "trans_type", "ease_type", "delay"), &Tween::targeting_method, DEFVAL(0));
- ADD_SIGNAL(MethodInfo("tween_started", 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_completed", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::STRING, "key")));
+ ADD_SIGNAL(MethodInfo("tween_started", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key")));
+ ADD_SIGNAL(MethodInfo("tween_step", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key"), PropertyInfo(Variant::REAL, "elapsed"), PropertyInfo(Variant::OBJECT, "value")));
+ ADD_SIGNAL(MethodInfo("tween_completed", PropertyInfo(Variant::OBJECT, "object"), PropertyInfo(Variant::NODE_PATH, "key")));
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "repeat"), "set_repeat", "is_repeat");
ADD_PROPERTY(PropertyInfo(Variant::INT, "playback_process_mode", PROPERTY_HINT_ENUM, "Physics,Idle"), "set_tween_process_mode", "get_tween_process_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "playback_speed", PROPERTY_HINT_RANGE, "-64,64,0.01"), "set_speed_scale", "get_speed_scale");
BIND_ENUM_CONSTANT(TWEEN_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(TWEEN_PROCESS_IDLE);
@@ -561,57 +564,50 @@ void Tween::_tween_process(float p_delta) {
data.finish = true;
}
- switch (data.type) {
- case INTER_PROPERTY:
- case INTER_METHOD: {
- Variant result = _run_equation(data);
- emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result);
- _apply_tween_value(data, result);
- if (data.finish)
- _apply_tween_value(data, data.final_val);
- } break;
-
- case INTER_CALLBACK:
- if (data.finish) {
- if (data.call_deferred) {
-
- switch (data.args) {
- case 0:
- object->call_deferred(data.key[0]);
- break;
- case 1:
- object->call_deferred(data.key[0], data.arg[0]);
- break;
- case 2:
- object->call_deferred(data.key[0], data.arg[0], data.arg[1]);
- break;
- case 3:
- object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2]);
- break;
- case 4:
- object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3]);
- break;
- case 5:
- object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]);
- break;
- }
- } else {
- Variant::CallError error;
- Variant *arg[5] = {
- &data.arg[0],
- &data.arg[1],
- &data.arg[2],
- &data.arg[3],
- &data.arg[4],
- };
- object->call(data.key[0], (const Variant **)arg, data.args, error);
+ if (data.type == INTER_CALLBACK) {
+ if (data.finish) {
+ if (data.call_deferred) {
+
+ switch (data.args) {
+ case 0:
+ object->call_deferred(data.key[0]);
+ break;
+ case 1:
+ object->call_deferred(data.key[0], data.arg[0]);
+ break;
+ case 2:
+ object->call_deferred(data.key[0], data.arg[0], data.arg[1]);
+ break;
+ case 3:
+ object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2]);
+ break;
+ case 4:
+ object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3]);
+ break;
+ case 5:
+ object->call_deferred(data.key[0], data.arg[0], data.arg[1], data.arg[2], data.arg[3], data.arg[4]);
+ break;
}
+ } else {
+ Variant::CallError error;
+ Variant *arg[5] = {
+ &data.arg[0],
+ &data.arg[1],
+ &data.arg[2],
+ &data.arg[3],
+ &data.arg[4],
+ };
+ object->call(data.key[0], (const Variant **)arg, data.args, error);
}
- break;
- default: {}
+ }
+ } else {
+ Variant result = _run_equation(data);
+ emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result);
+ _apply_tween_value(data, result);
}
if (data.finish) {
+ _apply_tween_value(data, data.final_val);
emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false));
// not repeat mode, remove completed action
if (!repeat)
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 44710b25f9..757d80e90a 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TWEEN_H
#define TWEEN_H
diff --git a/scene/animation/tween_interpolaters.cpp b/scene/animation/tween_interpolaters.cpp
index cbf941f3ed..11f2b0c17f 100644
--- a/scene/animation/tween_interpolaters.cpp
+++ b/scene/animation/tween_interpolaters.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tween.h"
const real_t pi = 3.1415926535898;
diff --git a/scene/audio/audio_player.cpp b/scene/audio/audio_player.cpp
index 81962901d9..408c00334a 100644
--- a/scene/audio/audio_player.cpp
+++ b/scene/audio/audio_player.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "audio_player.h"
#include "engine.h"
@@ -44,7 +45,7 @@ void AudioStreamPlayer::_mix_internal(bool p_fadeout) {
}
//mix
- stream_playback->mix(buffer, 1.0, buffer_size);
+ stream_playback->mix(buffer, pitch_scale, buffer_size);
//multiply volume interpolating to avoid clicks if this changes
float target_volume = p_fadeout ? -80.0 : volume_db;
@@ -125,8 +126,8 @@ void AudioStreamPlayer::_notification(int p_what) {
if (!active || (setseek < 0 && !stream_playback->is_playing())) {
active = false;
- emit_signal("finished");
set_process_internal(false);
+ emit_signal("finished");
}
}
@@ -176,6 +177,13 @@ float AudioStreamPlayer::get_volume_db() const {
return volume_db;
}
+void AudioStreamPlayer::set_pitch_scale(float p_pitch_scale) {
+ pitch_scale = p_pitch_scale;
+}
+float AudioStreamPlayer::get_pitch_scale() const {
+ return pitch_scale;
+}
+
void AudioStreamPlayer::play(float p_from_pos) {
if (stream_playback.is_valid()) {
@@ -296,6 +304,9 @@ void AudioStreamPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_volume_db", "volume_db"), &AudioStreamPlayer::set_volume_db);
ClassDB::bind_method(D_METHOD("get_volume_db"), &AudioStreamPlayer::get_volume_db);
+ ClassDB::bind_method(D_METHOD("set_pitch_scale", "pitch_scale"), &AudioStreamPlayer::set_pitch_scale);
+ ClassDB::bind_method(D_METHOD("get_pitch_scale"), &AudioStreamPlayer::get_pitch_scale);
+
ClassDB::bind_method(D_METHOD("play", "from_position"), &AudioStreamPlayer::play, DEFVAL(0.0));
ClassDB::bind_method(D_METHOD("seek", "to_position"), &AudioStreamPlayer::seek);
ClassDB::bind_method(D_METHOD("stop"), &AudioStreamPlayer::stop);
@@ -319,6 +330,7 @@ void AudioStreamPlayer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24"), "set_volume_db", "get_volume_db");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "pitch_scale", PROPERTY_HINT_RANGE, "0.01,32,0.01"), "set_pitch_scale", "get_pitch_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_target", PROPERTY_HINT_ENUM, "Stereo,Surround,Center"), "set_mix_target", "get_mix_target");
@@ -334,6 +346,7 @@ void AudioStreamPlayer::_bind_methods() {
AudioStreamPlayer::AudioStreamPlayer() {
mix_volume_db = 0;
+ pitch_scale = 1.0;
volume_db = 0;
autoplay = false;
setseek = -1;
diff --git a/scene/audio/audio_player.h b/scene/audio/audio_player.h
index 6e9d623433..21189aea6d 100644
--- a/scene/audio/audio_player.h
+++ b/scene/audio/audio_player.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef AUDIOPLAYER_H
#define AUDIOPLAYER_H
@@ -53,6 +54,7 @@ private:
volatile bool active;
float mix_volume_db;
+ float pitch_scale;
float volume_db;
bool autoplay;
StringName bus;
@@ -80,6 +82,9 @@ public:
void set_volume_db(float p_volume);
float get_volume_db() const;
+ void set_pitch_scale(float p_pitch_scale);
+ float get_pitch_scale() const;
+
void play(float p_from_pos = 0.0);
void seek(float p_seconds);
void stop();
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 148277f2dd..acdbd9de08 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "base_button.h"
#include "os/keyboard.h"
@@ -59,7 +60,7 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
- if (status.disabled || b->get_button_index() != 1)
+ if (status.disabled || ((1 << (b->get_button_index() - 1)) & button_mask) == 0)
return;
if (status.pressing_button)
@@ -210,6 +211,11 @@ void BaseButton::_gui_input(Ref<InputEvent> p_event) {
if (!toggle_mode) { //mouse press attempt
pressed();
+ if (get_script_instance()) {
+ Variant::CallError ce;
+ get_script_instance()->call(SceneStringNames::get_singleton()->_pressed, NULL, 0, ce);
+ }
+
emit_signal("pressed");
} else {
@@ -246,7 +252,7 @@ void BaseButton::_notification(int p_what) {
status.hovering = false;
update();
}
- if (p_what == NOTIFICATION_DRAG_BEGIN) {
+ if (p_what == NOTIFICATION_DRAG_BEGIN || p_what == NOTIFICATION_SCROLL_BEGIN) {
if (status.press_attempt) {
status.press_attempt = false;
@@ -306,14 +312,12 @@ void BaseButton::toggled(bool p_pressed) {
}
void BaseButton::set_disabled(bool p_disabled) {
+ if (status.disabled == p_disabled)
+ return;
status.disabled = p_disabled;
update();
_change_notify("disabled");
- if (p_disabled)
- set_focus_mode(FOCUS_NONE);
- else
- set_focus_mode(enabled_focus_mode);
}
bool BaseButton::is_disabled() const {
@@ -404,6 +408,16 @@ BaseButton::ActionMode BaseButton::get_action_mode() const {
return action_mode;
}
+void BaseButton::set_button_mask(int p_mask) {
+
+ button_mask = p_mask;
+}
+
+int BaseButton::get_button_mask() const {
+
+ return button_mask;
+}
+
void BaseButton::set_enabled_focus_mode(FocusMode p_mode) {
enabled_focus_mode = p_mode;
@@ -450,11 +464,11 @@ String BaseButton::get_tooltip(const Point2 &p_pos) const {
String tooltip = Control::get_tooltip(p_pos);
if (shortcut.is_valid() && shortcut->is_valid()) {
- if (tooltip.find("$sc") != -1) {
- tooltip = tooltip.replace_first("$sc", "(" + shortcut->get_as_text() + ")");
- } else {
- tooltip += " (" + shortcut->get_as_text() + ")";
+ String text = shortcut->get_name() + " (" + shortcut->get_as_text() + ")";
+ if (shortcut->get_name().nocasecmp_to(tooltip) != 0) {
+ text += "\n" + tooltip;
}
+ tooltip = text;
}
return tooltip;
}
@@ -492,6 +506,8 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_disabled"), &BaseButton::is_disabled);
ClassDB::bind_method(D_METHOD("set_action_mode", "mode"), &BaseButton::set_action_mode);
ClassDB::bind_method(D_METHOD("get_action_mode"), &BaseButton::get_action_mode);
+ ClassDB::bind_method(D_METHOD("set_button_mask", "mask"), &BaseButton::set_button_mask);
+ ClassDB::bind_method(D_METHOD("get_button_mask"), &BaseButton::get_button_mask);
ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode);
ClassDB::bind_method(D_METHOD("set_enabled_focus_mode", "mode"), &BaseButton::set_enabled_focus_mode);
ClassDB::bind_method(D_METHOD("get_enabled_focus_mode"), &BaseButton::get_enabled_focus_mode);
@@ -503,16 +519,17 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group);
BIND_VMETHOD(MethodInfo("_pressed"));
- BIND_VMETHOD(MethodInfo("_toggled", PropertyInfo(Variant::BOOL, "pressed")));
+ BIND_VMETHOD(MethodInfo("_toggled", PropertyInfo(Variant::BOOL, "button_pressed")));
ADD_SIGNAL(MethodInfo("pressed"));
ADD_SIGNAL(MethodInfo("button_up"));
ADD_SIGNAL(MethodInfo("button_down"));
- ADD_SIGNAL(MethodInfo("toggled", PropertyInfo(Variant::BOOL, "pressed")));
+ ADD_SIGNAL(MethodInfo("toggled", PropertyInfo(Variant::BOOL, "button_pressed")));
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "disabled"), "set_disabled", "is_disabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "toggle_mode"), "set_toggle_mode", "is_toggle_mode");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "pressed"), "set_pressed", "is_pressed");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "action_mode", PROPERTY_HINT_ENUM, "Button Press,Button Release"), "set_action_mode", "get_action_mode");
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT, "button_mask", PROPERTY_HINT_FLAGS, "Mouse Left, Mouse Right, Mouse Middle"), "set_button_mask", "get_button_mask");
ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_enabled_focus_mode", "get_enabled_focus_mode");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shortcut", PROPERTY_HINT_RESOURCE_TYPE, "ShortCut"), "set_shortcut", "get_shortcut");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "group", PROPERTY_HINT_RESOURCE_TYPE, "ButtonGroup"), "set_button_group", "get_button_group");
@@ -538,15 +555,16 @@ BaseButton::BaseButton() {
set_focus_mode(FOCUS_ALL);
enabled_focus_mode = FOCUS_ALL;
action_mode = ACTION_MODE_BUTTON_RELEASE;
+ button_mask = BUTTON_MASK_LEFT;
+}
+
+BaseButton::~BaseButton() {
if (button_group.is_valid()) {
button_group->buttons.erase(this);
}
}
-BaseButton::~BaseButton() {
-}
-
void ButtonGroup::get_buttons(List<BaseButton *> *r_buttons) {
for (Set<BaseButton *>::Element *E = buttons.front(); E; E = E->next()) {
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index 0c08dc53a3..79638bbcce 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BASE_BUTTON_H
#define BASE_BUTTON_H
@@ -48,6 +49,7 @@ public:
};
private:
+ int button_mask;
bool toggle_mode;
FocusMode enabled_focus_mode;
Ref<ShortCut> shortcut;
@@ -89,8 +91,8 @@ public:
/* Signals */
- bool is_pressed() const; ///< return wether button is pressed (toggled in)
- bool is_pressing() const; ///< return wether button is pressed (toggled in)
+ bool is_pressed() const; ///< return whether button is pressed (toggled in)
+ bool is_pressing() const; ///< return whether button is pressed (toggled in)
bool is_hovered() const;
void set_pressed(bool p_pressed); ///only works in toggle mode
@@ -103,6 +105,9 @@ public:
void set_action_mode(ActionMode p_mode);
ActionMode get_action_mode() const;
+ void set_button_mask(int p_mask);
+ int get_button_mask() const;
+
void set_enabled_focus_mode(FocusMode p_mode);
FocusMode get_enabled_focus_mode() const;
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 739fd84b38..12b9fe7c03 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "box_container.h"
#include "label.h"
#include "margin_container.h"
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index ebbbbed1f9..abc228f804 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BOX_CONTAINER_H
#define BOX_CONTAINER_H
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index 47977f0283..03b25a138f 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "button.h"
#include "print_string.h"
#include "servers/visual_server.h"
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 35488582de..0b41b14f02 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BUTTON_H
#define BUTTON_H
@@ -56,7 +57,6 @@ private:
float _internal_margin[4];
protected:
- virtual Size2 get_minimum_size() const;
void _set_internal_margin(Margin p_margin, float p_value);
void _notification(int p_what);
static void _bind_methods();
@@ -64,6 +64,8 @@ protected:
public:
//
+ virtual Size2 get_minimum_size() const;
+
void set_text(const String &p_text);
String get_text() const;
diff --git a/scene/gui/center_container.cpp b/scene/gui/center_container.cpp
index 8c9c9d8720..cf71f89830 100644
--- a/scene/gui/center_container.cpp
+++ b/scene/gui/center_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "center_container.h"
Size2 CenterContainer::get_minimum_size() const {
diff --git a/scene/gui/center_container.h b/scene/gui/center_container.h
index 4397539046..519e1493ec 100644
--- a/scene/gui/center_container.h
+++ b/scene/gui/center_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CENTER_CONTAINER_H
#define CENTER_CONTAINER_H
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index bf8156b92b..0790f87ea7 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* check_button.cpp */
+/* check_box.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "check_box.h"
#include "servers/visual_server.h"
diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h
index 3d3f170e8c..8375b46ca0 100644
--- a/scene/gui/check_box.h
+++ b/scene/gui/check_box.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CHECK_BOX_H
#define CHECK_BOX_H
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index 641d2d4f01..f9ed0ecdbb 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "check_button.h"
#include "print_string.h"
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index 3103a40d3c..a11749e3f6 100644
--- a/scene/gui/check_button.h
+++ b/scene/gui/check_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CHECK_BUTTON_H
#define CHECK_BUTTON_H
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index cb6283507e..34891832e2 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "color_picker.h"
#include "os/input.h"
@@ -39,33 +40,32 @@ void ColorPicker::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- //sample->set_texture(get_icon("color_sample"));
+
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
bt_add_preset->set_icon(get_icon("add_preset"));
_update_controls();
} break;
-
case NOTIFICATION_ENTER_TREE: {
+
btn_pick->set_icon(get_icon("screen_picker", "ColorPicker"));
bt_add_preset->set_icon(get_icon("add_preset"));
_update_color();
} break;
-
case NOTIFICATION_PARENTED: {
+
for (int i = 0; i < 4; i++)
set_margin((Margin)i, get_constant("margin"));
} break;
-
case NOTIFICATION_VISIBILITY_CHANGED: {
Popup *p = Object::cast_to<Popup>(get_parent());
if (p)
p->set_size(Size2(get_combined_minimum_size().width + get_constant("margin") * 2, get_combined_minimum_size().height + get_constant("margin") * 2));
} break;
-
case MainLoop::NOTIFICATION_WM_QUIT_REQUEST: {
+
if (screen != NULL) {
if (screen->is_visible()) {
screen->hide();
@@ -77,8 +77,7 @@ void ColorPicker::_notification(int p_what) {
void ColorPicker::set_focus_on_line_edit() {
- c_text->grab_focus();
- c_text->select();
+ c_text->call_deferred("grab_focus");
}
void ColorPicker::_update_controls() {
@@ -159,14 +158,16 @@ void ColorPicker::_update_color() {
updating = true;
for (int i = 0; i < 4; i++) {
- scroll[i]->set_max(255);
scroll[i]->set_step(0.01);
if (raw_mode_enabled) {
+ scroll[i]->set_max(100);
if (i == 3)
scroll[i]->set_max(1);
scroll[i]->set_value(color.components[i]);
} else {
- scroll[i]->set_value(color.components[i] * 255);
+ const int byte_value = color.components[i] * 255;
+ scroll[i]->set_max(next_power_of_2(MAX(255, byte_value)) - 1);
+ scroll[i]->set_value(byte_value);
}
}
@@ -210,6 +211,7 @@ Color ColorPicker::get_pick_color() const {
}
void ColorPicker::add_preset(const Color &p_color) {
+
if (presets.find(p_color)) {
presets.move_to_back(presets.find(p_color));
} else {
@@ -241,6 +243,7 @@ bool ColorPicker::is_raw_mode() const {
}
void ColorPicker::_update_text_value() {
+ bool visible = true;
if (text_is_constructor) {
String t = "Color(" + String::num(color.r) + "," + String::num(color.g) + "," + String::num(color.b);
if (edit_alpha && color.a < 1)
@@ -249,8 +252,13 @@ void ColorPicker::_update_text_value() {
t += ")";
c_text->set_text(t);
} else {
- c_text->set_text(color.to_html(edit_alpha && color.a < 1));
+ if (color.r > 1 || color.g > 1 || color.b > 1 || color.r < 0 || color.g < 0 || color.b < 0) {
+ visible = false;
+ } else {
+ c_text->set_text(color.to_html(edit_alpha && color.a < 1));
+ }
}
+ c_text->set_visible(visible);
}
void ColorPicker::_sample_draw() {
@@ -461,6 +469,31 @@ void ColorPicker::_screen_pick_pressed() {
screen->show_modal();
}
+void ColorPicker::_focus_enter() {
+ if (c_text->has_focus()) {
+ c_text->select_all();
+ return;
+ }
+ for (int i = 0; i < 4; i++) {
+ if (values[i]->get_line_edit()->has_focus()) {
+ values[i]->get_line_edit()->select_all();
+ break;
+ }
+ }
+}
+
+void ColorPicker::_focus_exit() {
+ for (int i = 0; i < 4; i++) {
+ values[i]->get_line_edit()->select(0, 0);
+ }
+ c_text->select(0, 0);
+}
+
+void ColorPicker::_html_focus_exit() {
+ _html_entered(c_text->get_text());
+ _focus_exit();
+}
+
void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPicker::set_pick_color);
@@ -482,6 +515,13 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("_w_input"), &ColorPicker::_w_input);
ClassDB::bind_method(D_METHOD("_preset_input"), &ColorPicker::_preset_input);
ClassDB::bind_method(D_METHOD("_screen_input"), &ColorPicker::_screen_input);
+ ClassDB::bind_method(D_METHOD("_focus_enter"), &ColorPicker::_focus_enter);
+ ClassDB::bind_method(D_METHOD("_focus_exit"), &ColorPicker::_focus_exit);
+ ClassDB::bind_method(D_METHOD("_html_focus_exit"), &ColorPicker::_html_focus_exit);
+
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "raw_mode"), "set_raw_mode", "is_raw_mode");
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
}
@@ -523,7 +563,6 @@ ColorPicker::ColorPicker() :
add_child(hb_edit);
w_edit = memnew(Control);
- //w_edit->set_ignore_mouse(false);
w_edit->set_custom_minimum_size(Size2(get_constant("h_width"), 0));
w_edit->set_h_size_flags(SIZE_FILL);
w_edit->set_v_size_flags(SIZE_EXPAND_FILL);
@@ -555,11 +594,14 @@ ColorPicker::ColorPicker() :
scroll[i] = memnew(HSlider);
scroll[i]->set_v_size_flags(SIZE_SHRINK_CENTER);
+ scroll[i]->set_focus_mode(FOCUS_NONE);
hbc->add_child(scroll[i]);
values[i] = memnew(SpinBox);
scroll[i]->share(values[i]);
hbc->add_child(values[i]);
+ values[i]->get_line_edit()->connect("focus_entered", this, "_focus_enter");
+ values[i]->get_line_edit()->connect("focus_exited", this, "_focus_exit");
scroll[i]->set_min(0);
scroll[i]->set_page(0);
@@ -585,11 +627,13 @@ ColorPicker::ColorPicker() :
c_text = memnew(LineEdit);
hhb->add_child(c_text);
c_text->connect("text_entered", this, "_html_entered");
+ c_text->connect("focus_entered", this, "_focus_enter");
+ c_text->connect("focus_exited", this, "_html_focus_exit");
+
text_type->set_text("#");
c_text->set_h_size_flags(SIZE_EXPAND_FILL);
_update_controls();
- //_update_color();
updating = false;
set_pick_color(Color(1, 1, 1));
@@ -599,7 +643,6 @@ ColorPicker::ColorPicker() :
preset = memnew(TextureRect);
bbc->add_child(preset);
- //preset->set_ignore_mouse(false);
preset->connect("gui_input", this, "_preset_input");
preset->connect("draw", this, "_update_presets");
@@ -613,12 +656,19 @@ ColorPicker::ColorPicker() :
void ColorPickerButton::_color_changed(const Color &p_color) {
+ color = p_color;
update();
- emit_signal("color_changed", p_color);
+ emit_signal("color_changed", color);
+}
+
+void ColorPickerButton::_modal_closed() {
+
+ emit_signal("popup_closed");
}
void ColorPickerButton::pressed() {
+ _update_picker();
popup->set_position(get_global_position() - picker->get_combined_minimum_size());
popup->popup();
picker->set_focus_on_line_edit();
@@ -631,43 +681,65 @@ void ColorPickerButton::_notification(int p_what) {
Ref<StyleBox> normal = get_stylebox("normal");
Rect2 r = Rect2(normal->get_offset(), get_size() - normal->get_minimum_size());
draw_texture_rect(Control::get_icon("bg", "ColorPickerButton"), r, true);
- draw_rect(r, picker->get_pick_color());
+ draw_rect(r, color);
}
- if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST) {
+ if (p_what == MainLoop::NOTIFICATION_WM_QUIT_REQUEST && popup) {
popup->hide();
}
}
void ColorPickerButton::set_pick_color(const Color &p_color) {
- picker->set_pick_color(p_color);
+ color = p_color;
+ if (picker) {
+ picker->set_pick_color(p_color);
+ }
+
update();
- emit_signal("color_changed", p_color);
}
Color ColorPickerButton::get_pick_color() const {
- return picker->get_pick_color();
+ return color;
}
void ColorPickerButton::set_edit_alpha(bool p_show) {
- picker->set_edit_alpha(p_show);
+ edit_alpha = p_show;
+ if (picker) {
+ picker->set_edit_alpha(p_show);
+ }
}
bool ColorPickerButton::is_editing_alpha() const {
- return picker->is_editing_alpha();
+ return edit_alpha;
}
ColorPicker *ColorPickerButton::get_picker() {
+
+ _update_picker();
return picker;
}
-PopupPanel *ColorPickerButton::get_popup() {
+PopupPanel *ColorPickerButton::get_popup() const {
+
return popup;
}
+void ColorPickerButton::_update_picker() {
+ if (!picker) {
+ popup = memnew(PopupPanel);
+ picker = memnew(ColorPicker);
+ popup->add_child(picker);
+ add_child(popup);
+ picker->connect("color_changed", this, "_color_changed");
+ popup->connect("modal_closed", this, "_modal_closed");
+ picker->set_pick_color(color);
+ picker->set_edit_alpha(edit_alpha);
+ }
+}
+
void ColorPickerButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_pick_color", "color"), &ColorPickerButton::set_pick_color);
@@ -677,18 +749,20 @@ void ColorPickerButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_edit_alpha", "show"), &ColorPickerButton::set_edit_alpha);
ClassDB::bind_method(D_METHOD("is_editing_alpha"), &ColorPickerButton::is_editing_alpha);
ClassDB::bind_method(D_METHOD("_color_changed"), &ColorPickerButton::_color_changed);
+ ClassDB::bind_method(D_METHOD("_modal_closed"), &ColorPickerButton::_modal_closed);
ADD_SIGNAL(MethodInfo("color_changed", PropertyInfo(Variant::COLOR, "color")));
+ ADD_SIGNAL(MethodInfo("popup_closed"));
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_pick_color", "get_pick_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "edit_alpha"), "set_edit_alpha", "is_editing_alpha");
}
ColorPickerButton::ColorPickerButton() {
- popup = memnew(PopupPanel);
- picker = memnew(ColorPicker);
- popup->add_child(picker);
-
- picker->connect("color_changed", this, "_color_changed");
- add_child(popup);
+ //Initialization is now done deferred
+ //this improves performance in the inspector as the color picker
+ //can be expensive to initialize
+ picker = NULL;
+ popup = NULL;
+ edit_alpha = true;
}
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index c02cdc8608..6b63e5fe60 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLOR_PICKER_H
#define COLOR_PICKER_H
@@ -87,6 +88,9 @@ private:
void _screen_input(const Ref<InputEvent> &p_event);
void _add_preset_pressed();
void _screen_pick_pressed();
+ void _focus_enter();
+ void _focus_exit();
+ void _html_focus_exit();
protected:
void _notification(int);
@@ -114,10 +118,16 @@ class ColorPickerButton : public Button {
PopupPanel *popup;
ColorPicker *picker;
+ Color color;
+ bool edit_alpha;
void _color_changed(const Color &p_color);
+ void _modal_closed();
+
virtual void pressed();
+ void _update_picker();
+
protected:
void _notification(int);
static void _bind_methods();
@@ -130,7 +140,7 @@ public:
bool is_editing_alpha() const;
ColorPicker *get_picker();
- PopupPanel *get_popup();
+ PopupPanel *get_popup() const;
ColorPickerButton();
};
diff --git a/scene/gui/color_rect.cpp b/scene/gui/color_rect.cpp
index 6b5247648e..463f3911dc 100644
--- a/scene/gui/color_rect.cpp
+++ b/scene/gui/color_rect.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "color_rect.h"
void ColorRect::set_frame_color(const Color &p_color) {
diff --git a/scene/gui/color_rect.h b/scene/gui/color_rect.h
index 382648fddf..a841008f76 100644
--- a/scene/gui/color_rect.h
+++ b/scene/gui/color_rect.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef COLOR_RECT_H
#define COLOR_RECT_H
diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp
index ba5d92620b..7df03bf7c6 100644
--- a/scene/gui/container.cpp
+++ b/scene/gui/container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,15 +27,16 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "container.h"
#include "message_queue.h"
#include "scene/scene_string_names.h"
void Container::_child_minsize_changed() {
- Size2 ms = get_combined_minimum_size();
- if (ms.width > get_size().width || ms.height > get_size().height)
- minimum_size_changed();
+ //Size2 ms = get_combined_minimum_size();
+ //if (ms.width > get_size().width || ms.height > get_size().height) {
+ minimum_size_changed();
queue_sort();
}
@@ -50,6 +51,8 @@ void Container::add_child_notify(Node *p_child) {
control->connect("size_flags_changed", this, "queue_sort");
control->connect("minimum_size_changed", this, "_child_minsize_changed");
control->connect("visibility_changed", this, "_child_minsize_changed");
+
+ minimum_size_changed();
queue_sort();
}
@@ -60,6 +63,7 @@ void Container::move_child_notify(Node *p_child) {
if (!Object::cast_to<Control>(p_child))
return;
+ minimum_size_changed();
queue_sort();
}
@@ -74,6 +78,8 @@ void Container::remove_child_notify(Node *p_child) {
control->disconnect("size_flags_changed", this, "queue_sort");
control->disconnect("minimum_size_changed", this, "_child_minsize_changed");
control->disconnect("visibility_changed", this, "_child_minsize_changed");
+
+ minimum_size_changed();
queue_sort();
}
diff --git a/scene/gui/container.h b/scene/gui/container.h
index 60a7a9efcb..c472162f58 100644
--- a/scene/gui/container.h
+++ b/scene/gui/container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CONTAINER_H
#define CONTAINER_H
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 81d2b6731f..d07b5a9f65 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "control.h"
#include "project_settings.h"
#include "scene/main/canvas_layer.h"
@@ -48,31 +49,41 @@
Dictionary Control::_edit_get_state() const {
Dictionary s;
- s["rect"] = get_rect();
s["rotation"] = get_rotation();
s["scale"] = get_scale();
+ s["pivot"] = get_pivot_offset();
Array anchors;
anchors.push_back(get_anchor(MARGIN_LEFT));
anchors.push_back(get_anchor(MARGIN_TOP));
anchors.push_back(get_anchor(MARGIN_RIGHT));
anchors.push_back(get_anchor(MARGIN_BOTTOM));
s["anchors"] = anchors;
+ Array margins;
+ margins.push_back(get_margin(MARGIN_LEFT));
+ margins.push_back(get_margin(MARGIN_TOP));
+ margins.push_back(get_margin(MARGIN_RIGHT));
+ margins.push_back(get_margin(MARGIN_BOTTOM));
+ s["margins"] = margins;
return s;
}
void Control::_edit_set_state(const Dictionary &p_state) {
Dictionary state = p_state;
- Rect2 rect = state["rect"];
- set_position(rect.position);
- set_size(rect.size);
set_rotation(state["rotation"]);
set_scale(state["scale"]);
+ set_pivot_offset(state["pivot"]);
Array anchors = state["anchors"];
- set_anchor(MARGIN_LEFT, anchors[0]);
- set_anchor(MARGIN_TOP, anchors[1]);
- set_anchor(MARGIN_RIGHT, anchors[2]);
- set_anchor(MARGIN_BOTTOM, anchors[3]);
+ data.anchor[MARGIN_LEFT] = anchors[0];
+ data.anchor[MARGIN_TOP] = anchors[1];
+ data.anchor[MARGIN_RIGHT] = anchors[2];
+ data.anchor[MARGIN_BOTTOM] = anchors[3];
+ Array margins = state["margins"];
+ data.margin[MARGIN_LEFT] = margins[0];
+ data.margin[MARGIN_TOP] = margins[1];
+ data.margin[MARGIN_RIGHT] = margins[2];
+ data.margin[MARGIN_BOTTOM] = margins[3];
+ _size_changed();
}
void Control::_edit_set_position(const Point2 &p_position) {
@@ -83,20 +94,17 @@ Point2 Control::_edit_get_position() const {
return get_position();
};
-void Control::_edit_set_rect(const Rect2 &p_edit_rect) {
-
- Transform2D xform = _get_internal_transform();
-
- Vector2 new_pos = xform.basis_xform(p_edit_rect.position);
-
- Vector2 pos = get_position() + new_pos;
+void Control::_edit_set_scale(const Size2 &p_scale) {
+ set_scale(p_scale);
+}
- Rect2 new_rect = get_rect();
- new_rect.position = pos.snapped(Vector2(1, 1));
- new_rect.size = p_edit_rect.size.snapped(Vector2(1, 1));
+Size2 Control::_edit_get_scale() const {
+ return data.scale;
+}
- set_position(new_rect.position);
- set_size(new_rect.size);
+void Control::_edit_set_rect(const Rect2 &p_edit_rect) {
+ set_position((get_position() + get_transform().basis_xform(p_edit_rect.position)).snapped(Vector2(1, 1)));
+ set_size(p_edit_rect.size.snapped(Vector2(1, 1)));
}
Rect2 Control::_edit_get_rect() const {
@@ -120,6 +128,9 @@ bool Control::_edit_use_rotation() const {
}
void Control::_edit_set_pivot(const Point2 &p_pivot) {
+ Vector2 delta_pivot = p_pivot - get_pivot_offset();
+ Vector2 move = Vector2((cos(data.rotation) - 1.0) * delta_pivot.x - sin(data.rotation) * delta_pivot.y, sin(data.rotation) * delta_pivot.x + (cos(data.rotation) - 1.0) * delta_pivot.y);
+ set_position(get_position() + move);
set_pivot_offset(p_pivot);
}
@@ -144,12 +155,21 @@ Size2 Control::get_custom_minimum_size() const {
return data.custom_minimum_size;
}
-Size2 Control::get_combined_minimum_size() const {
+void Control::_update_minimum_size_cache() {
Size2 minsize = get_minimum_size();
minsize.x = MAX(minsize.x, data.custom_minimum_size.x);
minsize.y = MAX(minsize.y, data.custom_minimum_size.y);
- return minsize;
+ data.minimum_size_cache = minsize;
+ data.minimum_size_valid = true;
+}
+
+Size2 Control::get_combined_minimum_size() const {
+
+ if (!data.minimum_size_valid) {
+ const_cast<Control *>(this)->_update_minimum_size_cache();
+ }
+ return data.minimum_size_cache;
}
Size2 Control::_edit_get_minimum_size() const {
@@ -248,14 +268,18 @@ void Control::_update_minimum_size() {
if (!is_inside_tree())
return;
- data.pending_min_size_update = false;
Size2 minsize = get_combined_minimum_size();
if (minsize.x > data.size_cache.x ||
minsize.y > data.size_cache.y) {
_size_changed();
}
- emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
+ data.updating_last_minimum_size = false;
+
+ if (minsize != data.last_minimum_size) {
+ data.last_minimum_size = minsize;
+ emit_signal(SceneStringNames::get_singleton()->minimum_size_changed);
+ }
}
bool Control::_get(const StringName &p_name, Variant &r_ret) const {
@@ -426,8 +450,12 @@ void Control::_notification(int p_notification) {
case NOTIFICATION_ENTER_TREE: {
- _size_changed();
-
+ } break;
+ case NOTIFICATION_POST_ENTER_TREE: {
+ if (is_visible_in_tree()) {
+ data.minimum_size_valid = false;
+ _size_changed();
+ }
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -609,13 +637,12 @@ void Control::_notification(int p_notification) {
if (is_inside_tree()) {
_modal_stack_remove();
- minimum_size_changed();
}
//remove key focus
//remove modalness
} else {
-
+ data.minimum_size_valid = false;
_size_changed();
}
@@ -860,6 +887,8 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &
class_name = ClassDB::get_parent_class_nocheck(class_name);
}
+ class_name = type;
+
Control *parent = Object::cast_to<Control>(theme_owner->get_parent());
if (parent)
@@ -868,8 +897,6 @@ Ref<StyleBox> Control::get_stylebox(const StringName &p_name, const StringName &
theme_owner = NULL;
}
- class_name = type;
-
while (class_name != StringName()) {
if (Theme::get_default()->has_stylebox(p_name, class_name))
return Theme::get_default()->get_stylebox(p_name, class_name);
@@ -1278,25 +1305,28 @@ void Control::_size_changed() {
Size2 minimum_size = get_combined_minimum_size();
- if (data.h_grow == GROW_DIRECTION_BEGIN) {
- if (minimum_size.width > new_size_cache.width) {
- new_pos_cache.x = new_pos_cache.x + new_size_cache.width - minimum_size.width;
- new_size_cache.width = minimum_size.width;
+ if (minimum_size.width > new_size_cache.width) {
+ if (data.h_grow == GROW_DIRECTION_BEGIN) {
+ new_pos_cache.x += new_size_cache.width - minimum_size.width;
+ } else if (data.h_grow == GROW_DIRECTION_BOTH) {
+ new_pos_cache.x += 0.5 * (new_size_cache.width - minimum_size.width);
}
- } else {
- new_size_cache.width = MAX(minimum_size.width, new_size_cache.width);
+
+ new_size_cache.width = minimum_size.width;
}
- if (data.v_grow == GROW_DIRECTION_BEGIN) {
- if (minimum_size.height > new_size_cache.height) {
- new_pos_cache.y = new_pos_cache.y + new_size_cache.height - minimum_size.height;
- new_size_cache.height = minimum_size.height;
+ if (minimum_size.height > new_size_cache.height) {
+ if (data.v_grow == GROW_DIRECTION_BEGIN) {
+ new_pos_cache.y += new_size_cache.height - minimum_size.height;
+ } else if (data.v_grow == GROW_DIRECTION_BOTH) {
+ new_pos_cache.y += 0.5 * (new_size_cache.height - minimum_size.height);
}
- } else {
- new_size_cache.height = MAX(minimum_size.height, new_size_cache.height);
+
+ new_size_cache.height = minimum_size.height;
}
- if (get_viewport()->is_snap_controls_to_pixels_enabled()) {
+ // We use a little workaround to avoid flickering when moving the pivot with _edit_set_pivot()
+ if (Math::abs(Math::sin(data.rotation * 4.0f)) < 0.00001f && get_viewport()->is_snap_controls_to_pixels_enabled()) {
new_size_cache = new_size_cache.floor();
new_pos_cache = new_pos_cache.floor();
}
@@ -1324,7 +1354,7 @@ float Control::_get_parent_range(int p_idx) const {
if (!is_inside_tree()) {
- return 1.0;
+ return 0;
}
if (data.parent_canvas_item) {
@@ -1333,7 +1363,7 @@ float Control::_get_parent_range(int p_idx) const {
return get_viewport()->get_visible_rect().size[p_idx & 1];
}
- return 1.0;
+ return 0;
}
float Control::_get_range(int p_idx) const {
@@ -1356,24 +1386,31 @@ float Control::_a2s(float p_val, float p_anchor, float p_range) const {
}
void Control::set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin, bool p_push_opposite_anchor) {
- bool pushed = false;
+ float parent_range = _get_parent_range((p_margin == MARGIN_LEFT || p_margin == MARGIN_RIGHT) ? 0 : 1);
+ float previous_margin_pos = data.margin[p_margin] + data.anchor[p_margin] * parent_range;
+ float previous_opposite_margin_pos = data.margin[(p_margin + 2) % 4] + data.anchor[(p_margin + 2) % 4] * parent_range;
+
data.anchor[p_margin] = CLAMP(p_anchor, 0.0, 1.0);
if (((p_margin == MARGIN_LEFT || p_margin == MARGIN_TOP) && data.anchor[p_margin] > data.anchor[(p_margin + 2) % 4]) ||
((p_margin == MARGIN_RIGHT || p_margin == MARGIN_BOTTOM) && data.anchor[p_margin] < data.anchor[(p_margin + 2) % 4])) {
if (p_push_opposite_anchor) {
data.anchor[(p_margin + 2) % 4] = data.anchor[p_margin];
- pushed = true;
} else {
data.anchor[p_margin] = data.anchor[(p_margin + 2) % 4];
}
}
- if (is_inside_tree()) {
- if (p_keep_margin) {
- _size_changed();
+ if (!p_keep_margin) {
+ data.margin[p_margin] = _s2a(previous_margin_pos, data.anchor[p_margin], parent_range);
+ if (p_push_opposite_anchor) {
+ data.margin[(p_margin + 2) % 4] = _s2a(previous_opposite_margin_pos, data.anchor[(p_margin + 2) % 4], parent_range);
}
}
+ if (is_inside_tree()) {
+ _size_changed();
+ }
+
update();
_change_notify();
}
@@ -2004,7 +2041,7 @@ Control *Control::find_prev_valid_focus() const {
if (from->is_set_as_toplevel() || !Object::cast_to<Control>(from->get_parent())) {
- //find last of the childs
+ //find last of the children
prev_child = _prev_control(from);
@@ -2154,6 +2191,7 @@ void Control::set_theme(const Ref<Theme> &p_theme) {
data.theme = p_theme;
if (!p_theme.is_null()) {
+ data.theme_owner = this;
_propagate_theme_changed(this, this);
} else {
@@ -2442,17 +2480,25 @@ void Control::minimum_size_changed() {
if (!is_inside_tree() || data.block_minimum_size_adjust)
return;
- if (data.pending_min_size_update)
+ Control *invalidate = this;
+
+ //invalidate cache upwards
+ while (invalidate && invalidate->data.minimum_size_valid) {
+ invalidate->data.minimum_size_valid = false;
+ if (invalidate->is_set_as_toplevel())
+ break; // do not go further up
+ invalidate = invalidate->data.parent;
+ }
+
+ if (!is_visible_in_tree())
return;
- data.pending_min_size_update = true;
- MessageQueue::get_singleton()->push_call(this, "_update_minimum_size");
+ if (data.updating_last_minimum_size)
+ return;
- if (!is_toplevel_control()) {
- Control *pc = get_parent_control();
- if (pc)
- pc->minimum_size_changed();
- }
+ data.updating_last_minimum_size = true;
+
+ MessageQueue::get_singleton()->push_call(this, "_update_minimum_size");
}
int Control::get_v_size_flags() const {
@@ -2737,7 +2783,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_icon_override", "name", "texture"), &Control::add_icon_override);
ClassDB::bind_method(D_METHOD("add_shader_override", "name", "shader"), &Control::add_shader_override);
- ClassDB::bind_method(D_METHOD("add_style_override", "name", "stylebox"), &Control::add_style_override);
+ ClassDB::bind_method(D_METHOD("add_stylebox_override", "name", "stylebox"), &Control::add_style_override);
ClassDB::bind_method(D_METHOD("add_font_override", "name", "font"), &Control::add_font_override);
ClassDB::bind_method(D_METHOD("add_color_override", "name", "color"), &Control::add_color_override);
ClassDB::bind_method(D_METHOD("add_constant_override", "name", "constant"), &Control::add_constant_override);
@@ -2749,6 +2795,7 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_constant", "name", "type"), &Control::get_constant, DEFVAL(""));
ClassDB::bind_method(D_METHOD("has_icon_override", "name"), &Control::has_icon_override);
+ ClassDB::bind_method(D_METHOD("has_shader_override", "name"), &Control::has_shader_override);
ClassDB::bind_method(D_METHOD("has_stylebox_override", "name"), &Control::has_stylebox_override);
ClassDB::bind_method(D_METHOD("has_font_override", "name"), &Control::has_font_override);
ClassDB::bind_method(D_METHOD("has_color_override", "name"), &Control::has_color_override);
@@ -2825,17 +2872,18 @@ void Control::_bind_methods() {
ADD_PROPERTYINZ(PropertyInfo(Variant::INT, "margin_bottom", PROPERTY_HINT_RANGE, "-4096,4096"), "set_margin", "get_margin", MARGIN_BOTTOM);
ADD_GROUP("Grow Direction", "grow_");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Begin,End"), "set_h_grow_direction", "get_h_grow_direction");
- ADD_PROPERTYNO(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Begin,End"), "set_v_grow_direction", "get_v_grow_direction");
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT, "grow_horizontal", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_h_grow_direction", "get_h_grow_direction");
+ ADD_PROPERTYNO(PropertyInfo(Variant::INT, "grow_vertical", PROPERTY_HINT_ENUM, "Begin,End,Both"), "set_v_grow_direction", "get_v_grow_direction");
ADD_GROUP("Rect", "rect_");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_position", "get_position");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_global_position", PROPERTY_HINT_NONE, "", 0), "set_global_position", "get_global_position");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "set_size", "get_size");
ADD_PROPERTYNZ(PropertyInfo(Variant::VECTOR2, "rect_min_size"), "set_custom_minimum_size", "get_custom_minimum_size");
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "rect_rotation", PROPERTY_HINT_RANGE, "-1080,1080,0.01"), "set_rotation_degrees", "get_rotation_degrees");
ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_scale"), "set_scale", "get_scale");
ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "rect_pivot_offset"), "set_pivot_offset", "get_pivot_offset");
- ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rect_clip_content"), "set_clip_contents", "is_clipping_contents");
ADD_GROUP("Hint", "hint_");
ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
@@ -2847,9 +2895,11 @@ void Control::_bind_methods() {
ADD_PROPERTYINZ(PropertyInfo(Variant::NODE_PATH, "focus_neighbour_bottom"), "set_focus_neighbour", "get_focus_neighbour", MARGIN_BOTTOM);
ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_next"), "set_focus_next", "get_focus_next");
ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "focus_previous"), "set_focus_previous", "get_focus_previous");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
ADD_GROUP("Mouse", "mouse_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_filter", PROPERTY_HINT_ENUM, "Stop,Pass,Ignore"), "set_mouse_filter", "get_mouse_filter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mouse_default_cursor_shape", PROPERTY_HINT_ENUM, "Arrow,Ibeam,Pointing hand,Cross,Wait,Busy,Drag,Can drop,Forbidden,Vertical resize,Horizontal resize,Secondary diagonal resize,Main diagonal resize,Move,Vertial split,Horizontal split,Help"), "set_default_cursor_shape", "get_default_cursor_shape");
ADD_GROUP("Size Flags", "size_flags_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size_flags_horizontal", PROPERTY_HINT_FLAGS, "Fill,Expand,Shrink Center,Shrink End"), "set_h_size_flags", "get_h_size_flags");
@@ -2870,6 +2920,8 @@ void Control::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
+ BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN);
+ BIND_CONSTANT(NOTIFICATION_SCROLL_END);
BIND_ENUM_CONSTANT(CURSOR_ARROW);
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
@@ -2923,6 +2975,7 @@ void Control::_bind_methods() {
BIND_ENUM_CONSTANT(GROW_DIRECTION_BEGIN);
BIND_ENUM_CONSTANT(GROW_DIRECTION_END);
+ BIND_ENUM_CONSTANT(GROW_DIRECTION_BOTH);
BIND_ENUM_CONSTANT(ANCHOR_BEGIN);
BIND_ENUM_CONSTANT(ANCHOR_END);
@@ -2956,7 +3009,6 @@ Control::Control() {
data.h_size_flags = SIZE_FILL;
data.v_size_flags = SIZE_FILL;
data.expand = 1;
- data.pending_min_size_update = false;
data.rotation = 0;
data.parent_canvas_item = NULL;
data.scale = Vector2(1, 1);
@@ -2966,6 +3018,8 @@ Control::Control() {
data.disable_visibility_clip = false;
data.h_grow = GROW_DIRECTION_END;
data.v_grow = GROW_DIRECTION_END;
+ data.minimum_size_valid = false;
+ data.updating_last_minimum_size = false;
data.clip_contents = false;
for (int i = 0; i < 4; i++) {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 9ac0eb0be3..9124256624 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CONTROL_H
#define CONTROL_H
@@ -59,7 +60,8 @@ public:
enum GrowDirection {
GROW_DIRECTION_BEGIN,
- GROW_DIRECTION_END
+ GROW_DIRECTION_END,
+ GROW_DIRECTION_BOTH
};
enum FocusMode {
@@ -146,6 +148,11 @@ private:
Point2 pos_cache;
Size2 size_cache;
+ Size2 minimum_size_cache;
+ bool minimum_size_valid;
+
+ Size2 last_minimum_size;
+ bool updating_last_minimum_size;
float margin[4];
float anchor[4];
@@ -162,7 +169,6 @@ private:
int h_size_flags;
int v_size_flags;
float expand;
- bool pending_min_size_update;
Point2 custom_minimum_size;
bool pass_on_modal_close_click;
@@ -242,6 +248,8 @@ private:
void _modal_stack_remove();
void _modal_set_prev_focus_owner(ObjectID p_prev);
+ void _update_minimum_size_cache();
+
protected:
virtual void add_child_notify(Node *p_child);
virtual void remove_child_notify(Node *p_child);
@@ -270,6 +278,8 @@ public:
NOTIFICATION_FOCUS_EXIT = 44,
NOTIFICATION_THEME_CHANGED = 45,
NOTIFICATION_MODAL_CLOSE = 46,
+ NOTIFICATION_SCROLL_BEGIN = 47,
+ NOTIFICATION_SCROLL_END = 48,
};
@@ -279,6 +289,9 @@ public:
virtual void _edit_set_position(const Point2 &p_position);
virtual Point2 _edit_get_position() const;
+ virtual void _edit_set_scale(const Size2 &p_scale);
+ virtual Size2 _edit_get_scale() const;
+
virtual void _edit_set_rect(const Rect2 &p_edit_rect);
virtual Rect2 _edit_get_rect() const;
virtual bool _edit_use_rect() const;
@@ -316,11 +329,11 @@ public:
/* POSITIONING */
- void set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin = false);
+ void set_anchors_preset(LayoutPreset p_preset, bool p_keep_margin = true);
void set_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0);
void set_anchors_and_margins_preset(LayoutPreset p_preset, LayoutPresetMode p_resize_mode = PRESET_MODE_MINSIZE, int p_margin = 0);
- void set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin = false, bool p_push_opposite_anchor = true);
+ void set_anchor(Margin p_margin, float p_anchor, bool p_keep_margin = true, bool p_push_opposite_anchor = true);
float get_anchor(Margin p_margin) const;
void set_margin(Margin p_margin, float p_value);
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index d4912339da..d9737fa21a 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "dialogs.h"
#include "line_edit.h"
#include "print_string.h"
@@ -289,10 +290,17 @@ bool WindowDialog::get_resizable() const {
Size2 WindowDialog::get_minimum_size() const {
Ref<Font> font = get_font("title_font", "WindowDialog");
- int msx = close_button->get_combined_minimum_size().x;
- msx += font->get_string_size(title).x;
- return Size2(msx, 1);
+ const int button_width = close_button->get_combined_minimum_size().x;
+ const int title_width = font->get_string_size(title).x;
+ const int padding = button_width / 2;
+ const int button_area = button_width + padding;
+
+ // as the title gets centered, title_width + close_button_width is not enough.
+ // we want a width w, such that w / 2 - title_width / 2 >= button_area, i.e.
+ // w >= 2 * button_area + title_width
+
+ return Size2(2 * button_area + title_width, 1);
}
TextureButton *WindowDialog::get_close_button() {
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 54cc290b05..feb080dd06 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef DIALOGS_H
#define DIALOGS_H
@@ -107,7 +108,7 @@ class AcceptDialog : public WindowDialog {
HBoxContainer *hbc;
Label *label;
Button *ok;
- //Button *cancel; no more cancel (there is X on tht titlebar)
+ //Button *cancel; no more cancel (there is X on that titlebar)
bool hide_on_ok;
void _custom_action(const String &p_action);
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 6af869c503..4bd92d888d 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "file_dialog.h"
#include "os/keyboard.h"
#include "print_string.h"
@@ -209,7 +210,7 @@ void FileDialog::_action_pressed() {
bool valid = false;
if (filter->get_selected() == filter->get_item_count() - 1) {
- valid = true; //match none
+ valid = true; // match none
} else if (filters.size() > 1 && filter->get_selected() == 0) {
// match all filters
for (int i = 0; i < filters.size(); i++) {
@@ -286,7 +287,7 @@ bool FileDialog::_is_open_should_be_disabled() {
TreeItem *ti = tree->get_selected();
// We have something that we can't select?
if (!ti)
- return true;
+ return mode != MODE_OPEN_DIR; // In "Open folder" mode, having nothing selected picks the current folder.
Dictionary d = ti->get_metadata(0);
@@ -318,17 +319,15 @@ void FileDialog::deselect_items() {
case MODE_OPEN_FILE:
case MODE_OPEN_FILES:
- get_ok()->set_text(TTR("Open"));
- get_ok()->set_disabled(false);
+ get_ok()->set_text(RTR("Open"));
break;
-
case MODE_OPEN_DIR:
- get_ok()->set_text(TTR("Select Current Folder"));
- get_ok()->set_disabled(false);
+ get_ok()->set_text(RTR("Select Current Folder"));
break;
}
}
}
+
void FileDialog::_tree_selected() {
TreeItem *ti = tree->get_selected();
@@ -340,13 +339,13 @@ void FileDialog::_tree_selected() {
file->set_text(d["name"]);
} else if (mode == MODE_OPEN_DIR) {
- get_ok()->set_text(TTR("Select this Folder"));
+ get_ok()->set_text(RTR("Select this Folder"));
}
get_ok()->set_disabled(_is_open_should_be_disabled());
}
-void FileDialog::_tree_dc_selected() {
+void FileDialog::_tree_item_activated() {
TreeItem *ti = tree->get_selected();
if (!ti)
@@ -755,7 +754,7 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_input"), &FileDialog::_unhandled_input);
ClassDB::bind_method(D_METHOD("_tree_selected"), &FileDialog::_tree_selected);
- ClassDB::bind_method(D_METHOD("_tree_db_selected"), &FileDialog::_tree_dc_selected);
+ ClassDB::bind_method(D_METHOD("_tree_item_activated"), &FileDialog::_tree_item_activated);
ClassDB::bind_method(D_METHOD("_dir_entered"), &FileDialog::_dir_entered);
ClassDB::bind_method(D_METHOD("_file_entered"), &FileDialog::_file_entered);
ClassDB::bind_method(D_METHOD("_action_pressed"), &FileDialog::_action_pressed);
@@ -792,6 +791,15 @@ void FileDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("invalidate"), &FileDialog::invalidate);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "filters"), "set_filters", "get_filters");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_dir"), "set_current_dir", "get_current_dir");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_file"), "set_current_file", "get_current_file");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "current_path"), "set_current_path", "get_current_path");
+
ADD_SIGNAL(MethodInfo("file_selected", PropertyInfo(Variant::STRING, "path")));
ADD_SIGNAL(MethodInfo("files_selected", PropertyInfo(Variant::POOL_STRING_ARRAY, "paths")));
ADD_SIGNAL(MethodInfo("dir_selected", PropertyInfo(Variant::STRING, "dir")));
@@ -805,12 +813,6 @@ void FileDialog::_bind_methods() {
BIND_ENUM_CONSTANT(ACCESS_RESOURCES);
BIND_ENUM_CONSTANT(ACCESS_USERDATA);
BIND_ENUM_CONSTANT(ACCESS_FILESYSTEM);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "mode_overrides_title"), "set_mode_overrides_title", "is_mode_overriding_title");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "mode", PROPERTY_HINT_ENUM, "Open one,Open many,Open folder,Open any,Save"), "set_mode", "get_mode");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "access", PROPERTY_HINT_ENUM, "Resources,User data,File system"), "set_access", "get_access");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_STRING_ARRAY, "filters"), "set_filters", "get_filters");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_hidden_files"), "set_show_hidden_files", "is_showing_hidden_files");
}
void FileDialog::set_show_hidden_files(bool p_show) {
@@ -841,7 +843,7 @@ FileDialog::FileDialog() {
HBoxContainer *hbc = memnew(HBoxContainer);
dir_up = memnew(ToolButton);
- dir_up->set_tooltip(TTR("Go to parent folder"));
+ dir_up->set_tooltip(RTR("Go to parent folder"));
hbc->add_child(dir_up);
dir_up->connect("pressed", this, "_go_up");
@@ -877,7 +879,7 @@ FileDialog::FileDialog() {
filter = memnew(OptionButton);
filter->set_stretch_ratio(3);
filter->set_h_size_flags(SIZE_EXPAND_FILL);
- filter->set_clip_text(true); //too many extensions overflow it
+ filter->set_clip_text(true); // too many extensions overflows it
hbc->add_child(filter);
vbc->add_child(hbc);
@@ -886,9 +888,8 @@ FileDialog::FileDialog() {
_update_drives();
connect("confirmed", this, "_action_pressed");
- //cancel->connect("pressed", this,"_cancel_pressed");
tree->connect("cell_selected", this, "_tree_selected", varray(), CONNECT_DEFERRED);
- tree->connect("item_activated", this, "_tree_db_selected", varray());
+ tree->connect("item_activated", this, "_tree_item_activated", varray());
tree->connect("nothing_selected", this, "deselect_items");
dir->connect("text_entered", this, "_dir_entered");
file->connect("text_entered", this, "_file_entered");
@@ -918,7 +919,6 @@ FileDialog::FileDialog() {
exterr->set_text(RTR("Must use a valid extension."));
add_child(exterr);
- //update_file_list();
update_filters();
update_dir();
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index c8c1f23105..ad483d5dab 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef FILE_DIALOG_H
#define FILE_DIALOG_H
@@ -106,7 +107,7 @@ private:
void _tree_selected();
void _select_drive(int p_idx);
- void _tree_dc_selected();
+ void _tree_item_activated();
void _dir_entered(String p_dir);
void _file_entered(const String &p_file);
void _action_pressed();
diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp
index c9ce5e2143..b5622604e2 100644
--- a/scene/gui/gradient_edit.cpp
+++ b/scene/gui/gradient_edit.cpp
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* color_ramp_edit.cpp */
+/* gradient_edit.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "gradient_edit.h"
#include "os/keyboard.h"
@@ -146,6 +147,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) {
grabbed = _get_point_from_pos(x);
//grab or select
if (grabbed != -1) {
+ grabbed = false;
return;
}
@@ -366,6 +368,13 @@ void GradientEdit::_notification(int p_what) {
draw_line(Vector2(-1, -1), Vector2(-1, h + 1), Color(1, 1, 1, 0.6));
}
}
+
+ if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
+
+ if (!is_visible()) {
+ grabbing = false;
+ }
+ }
}
void GradientEdit::_draw_checker(int x, int y, int w, int h) {
diff --git a/scene/gui/gradient_edit.h b/scene/gui/gradient_edit.h
index 026e4f783b..e7834ea0de 100644
--- a/scene/gui/gradient_edit.h
+++ b/scene/gui/gradient_edit.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* color_ramp_edit.h */
+/* gradient_edit.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,8 +27,9 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef SCENE_GUI_COLOR_RAMP_EDIT_H_
-#define SCENE_GUI_COLOR_RAMP_EDIT_H_
+
+#ifndef GRADIENT_EDIT_H
+#define GRADIENT_EDIT_H
#include "scene/gui/color_picker.h"
#include "scene/gui/popup.h"
@@ -72,9 +73,4 @@ public:
virtual ~GradientEdit();
};
-/*class ColorRampEditPanel : public Panel
-{
- GDCLASS(ColorRampEditPanel, Panel );
-};*/
-
-#endif /* SCENE_GUI_COLOR_RAMP_EDIT_H_ */
+#endif // GRADIENT_EDIT_H
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index da52fb39e0..38ce91a4df 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "graph_edit.h"
#include "os/input.h"
@@ -1146,9 +1147,18 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_node_connected", "from", "from_port", "to", "to_port"), &GraphEdit::is_node_connected);
ClassDB::bind_method(D_METHOD("disconnect_node", "from", "from_port", "to", "to_port"), &GraphEdit::disconnect_node);
ClassDB::bind_method(D_METHOD("get_connection_list"), &GraphEdit::_get_connection_list);
+ ClassDB::bind_method(D_METHOD("clear_connections"), &GraphEdit::clear_connections);
ClassDB::bind_method(D_METHOD("get_scroll_ofs"), &GraphEdit::get_scroll_ofs);
ClassDB::bind_method(D_METHOD("set_scroll_ofs", "ofs"), &GraphEdit::set_scroll_ofs);
+ ClassDB::bind_method(D_METHOD("add_valid_right_disconnect_type", "type"), &GraphEdit::add_valid_right_disconnect_type);
+ ClassDB::bind_method(D_METHOD("remove_valid_right_disconnect_type", "type"), &GraphEdit::remove_valid_right_disconnect_type);
+ ClassDB::bind_method(D_METHOD("add_valid_left_disconnect_type", "type"), &GraphEdit::add_valid_left_disconnect_type);
+ ClassDB::bind_method(D_METHOD("remove_valid_left_disconnect_type", "type"), &GraphEdit::remove_valid_left_disconnect_type);
+ ClassDB::bind_method(D_METHOD("add_valid_connection_type", "from_type", "to_type"), &GraphEdit::add_valid_connection_type);
+ ClassDB::bind_method(D_METHOD("remove_valid_connection_type", "from_type", "to_type"), &GraphEdit::remove_valid_connection_type);
+ ClassDB::bind_method(D_METHOD("is_valid_connection_type", "from_type", "to_type"), &GraphEdit::is_valid_connection_type);
+
ClassDB::bind_method(D_METHOD("set_zoom", "p_zoom"), &GraphEdit::set_zoom);
ClassDB::bind_method(D_METHOD("get_zoom"), &GraphEdit::get_zoom);
@@ -1179,6 +1189,12 @@ void GraphEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_selected", "node"), &GraphEdit::set_selected);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "right_disconnects"), "set_right_disconnects", "is_right_disconnects_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scroll_offset"), "set_scroll_ofs", "get_scroll_ofs");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "snap_distance"), "set_snap", "get_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_snap"), "set_use_snap", "is_using_snap");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "zoom"), "set_zoom", "get_zoom");
+
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")));
ADD_SIGNAL(MethodInfo("popup_request", PropertyInfo(Variant::VECTOR2, "p_position")));
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index e8e530848d..3bfde44854 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -1,12 +1,12 @@
/*************************************************************************/
-/* graph_edit.cpp */
+/* graph_edit.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef GRAPH_EDIT_H
#define GRAPH_EDIT_H
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 7655363631..24857d49fa 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "graph_node.h"
#include "method_bind_ext.gen.inc"
@@ -704,8 +705,12 @@ void GraphNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_overlay"), &GraphNode::get_overlay);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_close"), "set_show_close_button", "is_close_button_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "resizable"), "set_resizable", "is_resizable");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selected"), "set_selected", "is_selected");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "comment"), "set_comment", "is_comment");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "overlay", PROPERTY_HINT_ENUM, "Disabled,Breakpoint,Position"), "set_overlay", "get_overlay");
ADD_SIGNAL(MethodInfo("offset_changed"));
ADD_SIGNAL(MethodInfo("dragged", PropertyInfo(Variant::VECTOR2, "from"), PropertyInfo(Variant::VECTOR2, "to")));
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index a0840544dd..20d25a69b0 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef GRAPH_NODE_H
#define GRAPH_NODE_H
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 5dd5667f46..278e4123d7 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "grid_container.h"
void GridContainer::_notification(int p_what) {
@@ -35,114 +36,131 @@ void GridContainer::_notification(int p_what) {
case NOTIFICATION_SORT_CHILDREN: {
- Map<int, int> col_minw;
- Map<int, int> row_minh;
- Set<int> col_expanded;
- Set<int> row_expanded;
+ int valid_controls_index;
+
+ Map<int, int> col_minw; // max of min_width of all controls in each col (indexed by col)
+ Map<int, int> row_minh; // max of min_height of all controls in each row (indexed by row)
+ Set<int> col_expanded; // columns which have the SIZE_EXPAND flag set
+ Set<int> row_expanded; // rows which have the SIZE_EXPAND flag set
int hsep = get_constant("hseparation");
int vsep = get_constant("vseparation");
+ int max_col = MIN(get_child_count(), columns);
+ int max_row = get_child_count() / columns;
- int idx = 0;
- int max_row = 0;
- int max_col = 0;
-
- Size2 size = get_size();
-
+ // Compute the per-column/per-row data
+ valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
-
Control *c = Object::cast_to<Control>(get_child(i));
if (!c || !c->is_visible_in_tree())
continue;
- int row = idx / columns;
- int col = idx % columns;
+ int row = valid_controls_index / columns;
+ int col = valid_controls_index % columns;
+ valid_controls_index++;
Size2i ms = c->get_combined_minimum_size();
if (col_minw.has(col))
col_minw[col] = MAX(col_minw[col], ms.width);
else
col_minw[col] = ms.width;
-
if (row_minh.has(row))
row_minh[row] = MAX(row_minh[row], ms.height);
else
row_minh[row] = ms.height;
- //print_line("store row "+itos(row)+" mw "+itos(ms.height));
-
- if (c->get_h_size_flags() & SIZE_EXPAND)
+ if (c->get_h_size_flags() & SIZE_EXPAND) {
col_expanded.insert(col);
- if (c->get_v_size_flags() & SIZE_EXPAND)
+ }
+ if (c->get_v_size_flags() & SIZE_EXPAND) {
row_expanded.insert(row);
-
- max_col = MAX(col, max_col);
- max_row = MAX(row, max_row);
- idx++;
+ }
}
- Size2 ms;
- int expand_rows = 0;
- int expand_cols = 0;
-
+ // Evaluate the remaining space for expanded columns/rows
+ Size2 remaining_space = get_size();
for (Map<int, int>::Element *E = col_minw.front(); E; E = E->next()) {
- ms.width += E->get();
- if (col_expanded.has(E->key()))
- expand_cols++;
+ if (!col_expanded.has(E->key()))
+ remaining_space.width -= E->get();
}
for (Map<int, int>::Element *E = row_minh.front(); E; E = E->next()) {
- ms.height += E->get();
- if (row_expanded.has(E->key()))
- expand_rows++;
+ if (!row_expanded.has(E->key()))
+ remaining_space.height -= E->get();
+ }
+ remaining_space.height -= vsep * MAX(max_row - 1, 0);
+ remaining_space.width -= hsep * MAX(max_col - 1, 0);
+
+ bool can_fit = false;
+ while (!can_fit && col_expanded.size() > 0) {
+ // Check if all minwidth constraints are ok if we use the remaining space
+ can_fit = true;
+ int max_index = col_expanded.front()->get();
+ for (Set<int>::Element *E = col_expanded.front(); E; E = E->next()) {
+ if (col_minw[E->get()] > col_minw[max_index]) {
+ max_index = E->get();
+ }
+ if (can_fit && (remaining_space.width / col_expanded.size()) < col_minw[E->get()]) {
+ can_fit = false;
+ }
+ }
+
+ // If not, the column with maximum minwidth is not expanded
+ if (!can_fit) {
+ col_expanded.erase(max_index);
+ remaining_space.width -= col_minw[max_index];
+ }
}
- ms.height += vsep * max_row;
- ms.width += hsep * max_col;
+ can_fit = false;
+ while (!can_fit && row_expanded.size() > 0) {
+ // Check if all minwidth constraints are ok if we use the remaining space
+ can_fit = true;
+ int max_index = row_expanded.front()->get();
+ for (Set<int>::Element *E = row_expanded.front(); E; E = E->next()) {
+ if (row_minh[E->get()] > row_minh[max_index]) {
+ max_index = E->get();
+ }
+ if (can_fit && (remaining_space.height / row_expanded.size()) < row_minh[E->get()]) {
+ can_fit = false;
+ }
+ }
+
+ // If not, the row with maximum minwidth is not expanded
+ if (!can_fit) {
+ row_expanded.erase(max_index);
+ remaining_space.height -= row_minh[max_index];
+ }
+ }
- int row_expand = expand_rows ? (size.y - ms.y) / expand_rows : 0;
- int col_expand = expand_cols ? (size.x - ms.x) / expand_cols : 0;
+ // Finally, fit the nodes
+ int col_expand = col_expanded.size() > 0 ? remaining_space.width / col_expanded.size() : 0;
+ int row_expand = row_expanded.size() > 0 ? remaining_space.height / row_expanded.size() : 0;
int col_ofs = 0;
int row_ofs = 0;
- idx = 0;
+ valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
-
Control *c = Object::cast_to<Control>(get_child(i));
if (!c || !c->is_visible_in_tree())
continue;
- int row = idx / columns;
- int col = idx % columns;
+ int row = valid_controls_index / columns;
+ int col = valid_controls_index % columns;
+ valid_controls_index++;
if (col == 0) {
col_ofs = 0;
- if (row > 0 && row_minh.has(row - 1))
- row_ofs += row_minh[row - 1] + vsep + (row_expanded.has(row - 1) ? row_expand : 0);
+ if (row > 0)
+ row_ofs += ((row_expanded.has(row - 1)) ? row_expand : row_minh[row - 1]) + vsep;
}
- Size2 s;
- if (col_minw.has(col))
- s.width = col_minw[col];
- if (row_minh.has(row))
- s.height = row_minh[row];
-
- if (row_expanded.has(row))
- s.height += row_expand;
- if (col_expanded.has(col))
- s.width += col_expand;
-
Point2 p(col_ofs, row_ofs);
+ Size2 s((col_expanded.has(col)) ? col_expand : col_minw[col], (row_expanded.has(row)) ? row_expand : row_minh[row]);
- //print_line("col: "+itos(col)+" row: "+itos(row)+" col_ofs: "+itos(col_ofs)+" row_ofs: "+itos(row_ofs));
fit_child_in_rect(c, Rect2(p, s));
- //print_line("col: "+itos(col)+" row: "+itos(row)+" rect: "+Rect2(p,s));
-
- if (col_minw.has(col)) {
- col_ofs += col_minw[col] + hsep + (col_expanded.has(col) ? col_expand : 0);
- }
- idx++;
+ col_ofs += s.width + hsep;
}
} break;
@@ -166,6 +184,8 @@ void GridContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_columns", "columns"), &GridContainer::set_columns);
ClassDB::bind_method(D_METHOD("get_columns"), &GridContainer::get_columns);
+ ClassDB::bind_method(D_METHOD("get_child_control_at_cell", "row", "column"),
+ &GridContainer::get_child_control_at_cell);
ADD_PROPERTY(PropertyInfo(Variant::INT, "columns", PROPERTY_HINT_RANGE, "1,1024,1"), "set_columns", "get_columns");
}
@@ -178,17 +198,19 @@ Size2 GridContainer::get_minimum_size() const {
int hsep = get_constant("hseparation");
int vsep = get_constant("vseparation");
- int idx = 0;
int max_row = 0;
int max_col = 0;
+ int valid_controls_index = 0;
for (int i = 0; i < get_child_count(); i++) {
Control *c = Object::cast_to<Control>(get_child(i));
if (!c || !c->is_visible_in_tree())
continue;
- int row = idx / columns;
- int col = idx % columns;
+ int row = valid_controls_index / columns;
+ int col = valid_controls_index % columns;
+ valid_controls_index++;
+
Size2i ms = c->get_combined_minimum_size();
if (col_minw.has(col))
col_minw[col] = MAX(col_minw[col], ms.width);
@@ -201,7 +223,6 @@ Size2 GridContainer::get_minimum_size() const {
row_minh[row] = ms.height;
max_col = MAX(col, max_col);
max_row = MAX(row, max_row);
- idx++;
}
Size2 ms;
@@ -220,6 +241,21 @@ Size2 GridContainer::get_minimum_size() const {
return ms;
}
+Control *GridContainer::get_child_control_at_cell(int row, int column) {
+ Control *c;
+ int grid_index = row * columns + column;
+ for (int i = 0; i < get_child_count(); i++) {
+ c = Object::cast_to<Control>(get_child(i));
+ if (!c || !c->is_visible_in_tree())
+ continue;
+
+ if (grid_index == i) {
+ break;
+ }
+ }
+ return c;
+}
+
GridContainer::GridContainer() {
set_mouse_filter(MOUSE_FILTER_PASS);
diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h
index 45e26ed48e..7e3470dc89 100644
--- a/scene/gui/grid_container.h
+++ b/scene/gui/grid_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef GRID_CONTAINER_H
#define GRID_CONTAINER_H
@@ -46,6 +47,7 @@ public:
void set_columns(int p_columns);
int get_columns() const;
virtual Size2 get_minimum_size() const;
+ Control *get_child_control_at_cell(int row, int column);
GridContainer();
};
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 197e474fd6..57b9a9a11b 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "item_list.h"
#include "os/os.h"
#include "project_settings.h"
@@ -36,6 +37,7 @@ void ItemList::add_item(const String &p_item, const Ref<Texture> &p_texture, boo
Item item;
item.icon = p_texture;
item.icon_region = Rect2i();
+ item.icon_modulate = Color(1, 1, 1, 1);
item.text = p_item;
item.selectable = p_selectable;
item.selected = false;
@@ -53,6 +55,7 @@ void ItemList::add_icon_item(const Ref<Texture> &p_item, bool p_selectable) {
Item item;
item.icon = p_item;
item.icon_region = Rect2i();
+ item.icon_modulate = Color(1, 1, 1, 1);
//item.text=p_item;
item.selectable = p_selectable;
item.selected = false;
@@ -137,6 +140,21 @@ Rect2 ItemList::get_item_icon_region(int p_idx) const {
return items[p_idx].icon_region;
}
+void ItemList::set_item_icon_modulate(int p_idx, const Color &p_modulate) {
+
+ ERR_FAIL_INDEX(p_idx, items.size());
+
+ items[p_idx].icon_modulate = p_modulate;
+ update();
+}
+
+Color ItemList::get_item_icon_modulate(int p_idx) const {
+
+ ERR_FAIL_INDEX_V(p_idx, items.size(), Color());
+
+ return items[p_idx].icon_modulate;
+}
+
void ItemList::set_item_custom_bg_color(int p_idx, const Color &p_custom_bg_color) {
ERR_FAIL_INDEX(p_idx, items.size());
@@ -294,35 +312,21 @@ int ItemList::get_current() const {
return current;
}
-void ItemList::move_item(int p_item, int p_to_pos) {
+void ItemList::move_item(int p_from_idx, int p_to_idx) {
- ERR_FAIL_INDEX(p_item, items.size());
- ERR_FAIL_INDEX(p_to_pos, items.size() + 1);
+ ERR_FAIL_INDEX(p_from_idx, items.size());
+ ERR_FAIL_INDEX(p_to_idx, items.size());
- Item it = items[p_item];
- items.remove(p_item);
-
- if (p_to_pos > p_item) {
- p_to_pos--;
- }
-
- if (p_to_pos >= items.size()) {
- items.push_back(it);
- } else {
- items.insert(p_to_pos, it);
+ if (is_anything_selected() && get_selected_items()[0] == p_from_idx) {
+ current = p_to_idx;
}
- if (current < 0) {
- //do none
- } else if (p_item == current) {
- current = p_to_pos;
- } else if (p_to_pos > p_item && current > p_item && current < p_to_pos) {
- current--;
- } else if (p_to_pos < p_item && current < p_item && current > p_to_pos) {
- current++;
- }
+ Item item = items[p_from_idx];
+ items.remove(p_from_idx);
+ items.insert(p_to_idx, item);
update();
+ shape_changed = true;
}
int ItemList::get_item_count() const {
@@ -516,11 +520,11 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
emit_signal("item_rmb_selected", i, get_local_mouse_position());
} else {
- bool selected = !items[i].selected;
+ bool selected = items[i].selected;
select(i, select_mode == SELECT_SINGLE || !mb->get_command());
- if (selected) {
+ if (!selected || allow_reselect) {
if (select_mode == SELECT_SINGLE) {
emit_signal("item_selected", i);
} else
@@ -674,7 +678,7 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) {
search_string = ""; //any mousepress cancels
- if (current % current_columns != (current_columns - 1)) {
+ if (current % current_columns != (current_columns - 1) && current + 1 < items.size()) {
set_current(current + 1);
ensure_current_is_visible();
if (select_mode == SELECT_SINGLE) {
@@ -930,6 +934,9 @@ void ItemList::_notification(int p_what) {
scroll_bar->hide();
} else {
scroll_bar->show();
+
+ if (do_autoscroll_to_bottom)
+ scroll_bar->set_value(max);
}
break;
}
@@ -957,12 +964,36 @@ void ItemList::_notification(int p_what) {
Vector2 base_ofs = bg->get_offset();
base_ofs.y -= int(scroll_bar->get_value());
- Rect2 clip(Point2(), size - bg->get_minimum_size() + Vector2(0, scroll_bar->get_value()));
+ const Rect2 clip(-base_ofs, size); // visible frame, don't need to draw outside of there
+
+ int first_item_visible;
+ {
+ // do a binary search to find the first item whose rect reaches below clip.position.y
+ int lo = 0;
+ int hi = items.size();
+ while (lo < hi) {
+ const int mid = (lo + hi) / 2;
+ const Rect2 &rcache = items[mid].rect_cache;
+ if (rcache.position.y + rcache.size.y < clip.position.y) {
+ lo = mid + 1;
+ } else {
+ hi = mid;
+ }
+ }
+ // we might have ended up with column 2, or 3, ..., so let's find the first column
+ while (lo > 0 && items[lo - 1].rect_cache.position.y == items[lo].rect_cache.position.y) {
+ lo -= 1;
+ }
+ first_item_visible = lo;
+ }
- for (int i = 0; i < items.size(); i++) {
+ for (int i = first_item_visible; i < items.size(); i++) {
Rect2 rcache = items[i].rect_cache;
+ if (rcache.position.y > clip.position.y + clip.size.y)
+ break; // done
+
if (!clip.intersects(rcache))
continue;
@@ -1031,7 +1062,7 @@ void ItemList::_notification(int p_what) {
draw_rect.size = adj.size;
}
- Color modulate = Color(1, 1, 1, 1);
+ Color modulate = items[i].icon_modulate;
if (items[i].disabled)
modulate.a *= 0.5;
@@ -1090,6 +1121,7 @@ void ItemList::_notification(int p_what) {
text_ofs += base_ofs;
text_ofs += items[i].rect_cache.position;
+ FontDrawer drawer(font, Color(1, 1, 1));
for (int j = 0; j < ss; j++) {
if (j == line_limit_cache[line]) {
@@ -1098,7 +1130,7 @@ void ItemList::_notification(int p_what) {
if (line >= max_text_lines)
break;
}
- ofs += font->draw_char(get_canvas_item(), text_ofs + Vector2(ofs + (max_len - line_size_cache[line]) / 2, line * (font_height + line_separation)).floor(), items[i].text[j], items[i].text[j + 1], modulate);
+ ofs += drawer.draw_char(get_canvas_item(), text_ofs + Vector2(ofs + (max_len - line_size_cache[line]) / 2, line * (font_height + line_separation)).floor(), items[i].text[j], items[i].text[j + 1], modulate);
}
//special multiline mode
@@ -1134,8 +1166,28 @@ void ItemList::_notification(int p_what) {
}
}
- for (int i = 0; i < separators.size(); i++) {
- draw_line(Vector2(bg->get_margin(MARGIN_LEFT), base_ofs.y + separators[i]), Vector2(width, base_ofs.y + separators[i]), guide_color);
+ int first_visible_separator = 0;
+ {
+ // do a binary search to find the first separator that is below clip_position.y
+ int lo = 0;
+ int hi = separators.size();
+ while (lo < hi) {
+ const int mid = (lo + hi) / 2;
+ if (separators[mid] < clip.position.y) {
+ lo = mid + 1;
+ } else {
+ hi = mid;
+ }
+ }
+ first_visible_separator = lo;
+ }
+
+ for (int i = first_visible_separator; i < separators.size(); i++) {
+ if (separators[i] > clip.position.y + clip.size.y)
+ break; // done
+
+ const int y = base_ofs.y + separators[i];
+ draw_line(Vector2(bg->get_margin(MARGIN_LEFT), y), Vector2(width, y), guide_color);
}
}
}
@@ -1192,7 +1244,7 @@ bool ItemList::is_pos_at_end_of_items(const Point2 &p_pos) const {
String ItemList::get_tooltip(const Point2 &p_pos) const {
- int closest = get_item_at_position(p_pos);
+ int closest = get_item_at_position(p_pos, true);
if (closest != -1) {
if (!items[closest].tooltip_enabled) {
@@ -1237,6 +1289,7 @@ int ItemList::find_metadata(const Variant &p_metadata) const {
}
void ItemList::set_allow_rmb_select(bool p_allow) {
+
allow_rmb_select = p_allow;
}
@@ -1245,6 +1298,16 @@ bool ItemList::get_allow_rmb_select() const {
return allow_rmb_select;
}
+void ItemList::set_allow_reselect(bool p_allow) {
+
+ allow_reselect = p_allow;
+}
+
+bool ItemList::get_allow_reselect() const {
+
+ return allow_reselect;
+}
+
void ItemList::set_icon_scale(real_t p_scale) {
icon_scale = p_scale;
}
@@ -1313,6 +1376,11 @@ Size2 ItemList::get_minimum_size() const {
return Size2();
}
+void ItemList::set_autoscroll_to_bottom(const bool p_enable) {
+
+ do_autoscroll_to_bottom = p_enable;
+}
+
void ItemList::set_auto_height(bool p_enable) {
auto_height = p_enable;
@@ -1339,6 +1407,9 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_icon_region", "idx", "rect"), &ItemList::set_item_icon_region);
ClassDB::bind_method(D_METHOD("get_item_icon_region", "idx"), &ItemList::get_item_icon_region);
+ ClassDB::bind_method(D_METHOD("set_item_icon_modulate", "idx", "modulate"), &ItemList::set_item_icon_modulate);
+ ClassDB::bind_method(D_METHOD("get_item_icon_modulate", "idx"), &ItemList::get_item_icon_modulate);
+
ClassDB::bind_method(D_METHOD("set_item_selectable", "idx", "selectable"), &ItemList::set_item_selectable);
ClassDB::bind_method(D_METHOD("is_item_selectable", "idx"), &ItemList::is_item_selectable);
@@ -1359,9 +1430,13 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("select", "idx", "single"), &ItemList::select, DEFVAL(true));
ClassDB::bind_method(D_METHOD("unselect", "idx"), &ItemList::unselect);
+ ClassDB::bind_method(D_METHOD("unselect_all"), &ItemList::unselect_all);
+
ClassDB::bind_method(D_METHOD("is_selected", "idx"), &ItemList::is_selected);
ClassDB::bind_method(D_METHOD("get_selected_items"), &ItemList::get_selected_items);
+ ClassDB::bind_method(D_METHOD("move_item", "from_idx", "to_idx"), &ItemList::move_item);
+
ClassDB::bind_method(D_METHOD("get_item_count"), &ItemList::get_item_count);
ClassDB::bind_method(D_METHOD("remove_item", "idx"), &ItemList::remove_item);
@@ -1395,9 +1470,14 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_allow_rmb_select", "allow"), &ItemList::set_allow_rmb_select);
ClassDB::bind_method(D_METHOD("get_allow_rmb_select"), &ItemList::get_allow_rmb_select);
+ ClassDB::bind_method(D_METHOD("set_allow_reselect", "allow"), &ItemList::set_allow_reselect);
+ ClassDB::bind_method(D_METHOD("get_allow_reselect"), &ItemList::get_allow_reselect);
+
ClassDB::bind_method(D_METHOD("set_auto_height", "enable"), &ItemList::set_auto_height);
ClassDB::bind_method(D_METHOD("has_auto_height"), &ItemList::has_auto_height);
+ ClassDB::bind_method(D_METHOD("is_anything_selected"), &ItemList::is_anything_selected);
+
ClassDB::bind_method(D_METHOD("get_item_at_position", "position", "exact"), &ItemList::get_item_at_position, DEFVAL(false));
ClassDB::bind_method(D_METHOD("ensure_current_is_visible"), &ItemList::ensure_current_is_visible);
@@ -1410,9 +1490,10 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_items"), &ItemList::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &ItemList::_get_items);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
ADD_PROPERTYNO(PropertyInfo(Variant::INT, "max_text_lines"), "set_max_text_lines", "get_max_text_lines");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "auto_height"), "set_auto_height", "has_auto_height");
@@ -1423,6 +1504,7 @@ void ItemList::_bind_methods() {
ADD_GROUP("Icon", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_mode", PROPERTY_HINT_ENUM, "Top,Left"), "set_icon_mode", "get_icon_mode");
ADD_PROPERTYNO(PropertyInfo(Variant::REAL, "icon_scale"), "set_icon_scale", "get_icon_scale");
+ ADD_PROPERTYNO(PropertyInfo(Variant::VECTOR2, "fixed_icon_size"), "set_fixed_icon_size", "get_fixed_icon_size");
BIND_ENUM_CONSTANT(ICON_MODE_TOP);
BIND_ENUM_CONSTANT(ICON_MODE_LEFT);
@@ -1466,6 +1548,8 @@ ItemList::ItemList() {
ensure_selected_visible = false;
defer_select_single = -1;
allow_rmb_select = false;
+ allow_reselect = false;
+ do_autoscroll_to_bottom = false;
icon_scale = 1.0f;
set_clip_contents(true);
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index b1e1e5eeb0..58771c1777 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ITEMLIST_H
#define ITEMLIST_H
@@ -53,6 +54,7 @@ private:
Ref<Texture> icon;
Rect2i icon_region;
+ Color icon_modulate;
Ref<Texture> tag_icon;
String text;
bool selectable;
@@ -105,8 +107,12 @@ private:
bool allow_rmb_select;
+ bool allow_reselect;
+
real_t icon_scale;
+ bool do_autoscroll_to_bottom;
+
Array _get_items() const;
void _set_items(const Array &p_items);
@@ -130,6 +136,9 @@ public:
void set_item_icon_region(int p_idx, const Rect2 &p_region);
Rect2 get_item_icon_region(int p_idx) const;
+ void set_item_icon_modulate(int p_idx, const Color &p_modulate);
+ Color get_item_icon_modulate(int p_idx) const;
+
void set_item_selectable(int p_idx, bool p_selectable);
bool is_item_selectable(int p_idx) const;
@@ -164,7 +173,7 @@ public:
void set_current(int p_current);
int get_current() const;
- void move_item(int p_item, int p_to_pos);
+ void move_item(int p_from_idx, int p_to_idx);
int get_item_count() const;
void remove_item(int p_idx);
@@ -195,6 +204,9 @@ public:
void set_allow_rmb_select(bool p_allow);
bool get_allow_rmb_select() const;
+ void set_allow_reselect(bool p_allow);
+ bool get_allow_reselect() const;
+
void ensure_current_is_visible();
void sort_items_by_text();
@@ -212,6 +224,8 @@ public:
Size2 get_minimum_size() const;
+ void set_autoscroll_to_bottom(const bool p_enable);
+
VScrollBar *get_v_scroll() { return scroll_bar; }
ItemList();
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index e1f77594da..9af479c1cc 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "label.h"
#include "print_string.h"
#include "project_settings.h"
@@ -92,6 +93,7 @@ void Label::_notification(int p_what) {
bool use_outline = get_constant("shadow_as_outline");
Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
int line_spacing = get_constant("line_spacing");
+ Color font_outline_modulate = get_color("font_outline_modulate");
style->draw(ci, Rect2(Point2(0, 0), get_size()));
@@ -101,7 +103,8 @@ void Label::_notification(int p_what) {
int lines_visible = (size.y + line_spacing) / font_h;
- int space_w = font->get_char_size(' ').width;
+ // ceiling to ensure autowrapping does not cut text
+ int space_w = Math::ceil(font->get_char_size(' ').width);
int chars_total = 0;
int vbegin = 0, vsep = 0;
@@ -149,6 +152,7 @@ void Label::_notification(int p_what) {
int line = 0;
int line_to = lines_skipped + (lines_visible > 0 ? lines_visible : 1);
+ FontDrawer drawer(font, font_outline_modulate);
while (wc) {
/* handle lines not meant to be drawn quickly */
if (line >= line_to)
@@ -207,7 +211,7 @@ void Label::_notification(int p_what) {
} break;
}
- int y_ofs = style->get_offset().y;
+ float y_ofs = style->get_offset().y;
y_ofs += (line - lines_skipped) * font_h + font->get_ascent();
y_ofs += vbegin + line * vsep;
@@ -243,11 +247,11 @@ void Label::_notification(int p_what) {
n = String::char_uppercase(c);
}
- float move = font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + shadow_ofs, c, n, font_color_shadow);
+ float move = font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + shadow_ofs, c, n, font_color_shadow, false);
if (use_outline) {
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + Vector2(-shadow_ofs.x, shadow_ofs.y), c, n, font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + Vector2(shadow_ofs.x, -shadow_ofs.y), c, n, font_color_shadow);
- font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + Vector2(-shadow_ofs.x, -shadow_ofs.y), c, n, font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + Vector2(-shadow_ofs.x, shadow_ofs.y), c, n, font_color_shadow, false);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + Vector2(shadow_ofs.x, -shadow_ofs.y), c, n, font_color_shadow, false);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs) + Vector2(-shadow_ofs.x, -shadow_ofs.y), c, n, font_color_shadow, false);
}
x_ofs_shadow += move;
chars_total_shadow++;
@@ -264,7 +268,7 @@ void Label::_notification(int p_what) {
n = String::char_uppercase(c);
}
- x_ofs += font->draw_char(ci, Point2(x_ofs, y_ofs), c, n, font_color);
+ x_ofs += drawer.draw_char(ci, Point2(x_ofs, y_ofs), c, n, font_color);
chars_total++;
}
}
@@ -328,7 +332,8 @@ int Label::get_longest_line_width() const {
}
} else {
- int char_width = font->get_char_size(current, xl_text[i + 1]).width;
+ // ceiling to ensure autowrapping does not cut text
+ int char_width = Math::ceil(font->get_char_size(current, xl_text[i + 1]).width);
line_width += char_width;
}
}
@@ -381,7 +386,8 @@ void Label::regenerate_word_cache() {
int word_pos = 0;
int line_width = 0;
int space_count = 0;
- int space_width = font->get_char_size(' ').width;
+ // ceiling to ensure autowrapping does not cut text
+ int space_width = Math::ceil(font->get_char_size(' ').width);
int line_spacing = get_constant("line_spacing");
line_count = 1;
total_char_cache = 0;
@@ -443,8 +449,8 @@ void Label::regenerate_word_cache() {
if (current_word_size == 0) {
word_pos = i;
}
-
- char_width = font->get_char_size(current, xl_text[i + 1]).width;
+ // ceiling to ensure autowrapping does not cut text
+ char_width = Math::ceil(font->get_char_size(current, xl_text[i + 1]).width);
current_word_size += char_width;
line_width += char_width;
total_char_cache++;
@@ -563,6 +569,7 @@ void Label::set_visible_characters(int p_amount) {
if (get_total_character_count() > 0) {
percent_visible = (float)p_amount / (float)total_char_cache;
}
+ _change_notify("percent_visible");
update();
}
@@ -583,6 +590,7 @@ void Label::set_percent_visible(float p_percent) {
visible_chars = get_total_character_count() * p_percent;
percent_visible = p_percent;
}
+ _change_notify("visible_chars");
update();
}
@@ -664,6 +672,7 @@ void Label::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "autowrap"), "set_autowrap", "has_autowrap");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1", PROPERTY_USAGE_EDITOR), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE, "-1,999,1"), "set_max_lines_visible", "get_max_lines_visible");
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 7c1905af7d..d5e0b60773 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LABEL_H
#define LABEL_H
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 85ae6d6241..2b644e7f96 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,8 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "line_edit.h"
#include "label.h"
+#include "message_queue.h"
#include "os/keyboard.h"
#include "os/os.h"
#include "print_string.h"
@@ -85,7 +87,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if ((cursor_pos < selection.begin) || (cursor_pos > selection.end) || !selection.enabled) {
- selection_clear();
+ deselect();
selection.cursor_start = cursor_pos;
selection.creating = true;
} else if (selection.enabled) {
@@ -99,7 +101,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} else {
if ((!selection.creating) && (!selection.doubleclick)) {
- selection_clear();
+ deselect();
}
selection.creating = false;
selection.doubleclick = false;
@@ -175,7 +177,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (editable) {
- selection_clear();
+ deselect();
text = text.substr(cursor_pos, text.length() - cursor_pos);
Ref<Font> font = get_font("font");
@@ -204,7 +206,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
if (editable) {
- selection_clear();
+ deselect();
text = text.substr(0, cursor_pos);
_text_changed();
}
@@ -213,6 +215,12 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
case (KEY_A): { //Select All
select();
} break;
+ case (KEY_LEFT): { // Go to start of text - like HOME key
+ set_cursor_position(0);
+ } break;
+ case (KEY_RIGHT): { // Go to end of text - like END key
+ set_cursor_position(text.length());
+ } break;
default: { handled = false; }
}
@@ -368,6 +376,20 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
shift_selection_check_post(k->get_shift());
} break;
+ case KEY_UP: {
+
+ shift_selection_check_pre(k->get_shift());
+ if (get_cursor_position() == 0) handled = false;
+ set_cursor_position(0);
+ shift_selection_check_post(k->get_shift());
+ } break;
+ case KEY_DOWN: {
+
+ shift_selection_check_pre(k->get_shift());
+ if (get_cursor_position() == text.length()) handled = false;
+ set_cursor_position(text.length());
+ shift_selection_check_post(k->get_shift());
+ } break;
case KEY_DELETE: {
if (!editable)
@@ -586,6 +608,7 @@ void LineEdit::_notification(int p_what) {
}
int x_ofs = 0;
+ int cached_text_width = text.empty() ? cached_placeholder_width : cached_width;
switch (align) {
@@ -599,15 +622,15 @@ void LineEdit::_notification(int p_what) {
if (window_pos != 0)
x_ofs = style->get_offset().x;
else
- x_ofs = int(size.width - (cached_width)) / 2;
+ x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (cached_text_width)) / 2);
} break;
case ALIGN_RIGHT: {
- x_ofs = int(size.width - style->get_offset().x - (cached_width));
+ x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_text_width)));
} break;
}
- int ofs_max = width - style->get_minimum_size().width;
+ int ofs_max = width - style->get_margin(MARGIN_RIGHT);
int char_ofs = window_pos;
int y_area = height - style->get_minimum_size().height;
@@ -633,6 +656,7 @@ void LineEdit::_notification(int p_what) {
}
int caret_height = font->get_height() > y_area ? y_area : font->get_height();
+ FontDrawer drawer(font, Color(1, 1, 1));
while (true) {
//end of string, break!
@@ -646,8 +670,8 @@ void LineEdit::_notification(int p_what) {
if (ofs >= ime_text.length())
break;
- CharType cchar = (pass && !text.empty()) ? '*' : ime_text[ofs];
- CharType next = (pass && !text.empty()) ? '*' : ime_text[ofs + 1];
+ CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs];
+ CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1];
int im_char_width = font->get_char_size(cchar, next).width;
if ((x_ofs + im_char_width) > ofs_max)
@@ -660,7 +684,7 @@ void LineEdit::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 1)), font_color);
}
- font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, font_color);
+ drawer.draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, font_color);
x_ofs += im_char_width;
ofs++;
@@ -668,8 +692,8 @@ void LineEdit::_notification(int p_what) {
}
}
- CharType cchar = (pass && !text.empty()) ? '*' : t[char_ofs];
- CharType next = (pass && !text.empty()) ? '*' : t[char_ofs + 1];
+ CharType cchar = (pass && !text.empty()) ? secret_character[0] : t[char_ofs];
+ CharType next = (pass && !text.empty()) ? secret_character[0] : t[char_ofs + 1];
int char_width = font->get_char_size(cchar, next).width;
// end of widget, break!
@@ -681,7 +705,7 @@ void LineEdit::_notification(int p_what) {
if (selected)
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, caret_height)), selection_color);
- font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
+ drawer.draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, selected ? font_color_selected : font_color);
if (char_ofs == cursor_pos && draw_caret) {
if (ime_text.length() == 0) {
@@ -700,8 +724,8 @@ void LineEdit::_notification(int p_what) {
if (ofs >= ime_text.length())
break;
- CharType cchar = (pass && !text.empty()) ? '*' : ime_text[ofs];
- CharType next = (pass && !text.empty()) ? '*' : ime_text[ofs + 1];
+ CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs];
+ CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1];
int im_char_width = font->get_char_size(cchar, next).width;
if ((x_ofs + im_char_width) > ofs_max)
@@ -714,7 +738,7 @@ void LineEdit::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs + caret_height), Size2(im_char_width, 1)), font_color);
}
- font->draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, font_color);
+ drawer.draw_char(ci, Point2(x_ofs, y_ofs + font_ascent), cchar, next, font_color);
x_ofs += im_char_width;
ofs++;
@@ -787,7 +811,12 @@ void LineEdit::paste_text() {
if (selection.enabled) selection_delete();
append_at_cursor(paste_buffer);
- _text_changed();
+ if (!text_changed_dirty) {
+ if (is_inside_tree()) {
+ MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ }
+ text_changed_dirty = true;
+ }
}
}
@@ -827,7 +856,7 @@ void LineEdit::shift_selection_check_pre(bool p_shift) {
selection.cursor_start = cursor_pos;
}
if (!p_shift)
- selection_clear();
+ deselect();
}
void LineEdit::shift_selection_check_post(bool p_shift) {
@@ -860,7 +889,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
} break;
case ALIGN_RIGHT: {
- pixel_ofs = int(size.width - style->get_offset().x - (cached_width));
+ pixel_ofs = int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_width));
} break;
}
@@ -880,13 +909,6 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
}
set_cursor_position(ofs);
-
- /*
- int new_cursor_pos=p_x;
- int charwidth=draw_area->get_font_char_width(' ',0);
- new_cursor_pos=( ( (new_cursor_pos-2)+ (charwidth/2) ) /charwidth );
- if (new_cursor_pos>(int)text.length()) new_cursor_pos=text.length();
- set_cursor_position(window_pos+new_cursor_pos); */
}
bool LineEdit::cursor_get_blink_enabled() const {
@@ -941,11 +963,6 @@ void LineEdit::delete_char() {
set_cursor_position(get_cursor_position() - 1);
- if (cursor_pos == window_pos) {
-
- //set_window_pos(cursor_pos-get_window_length());
- }
-
_text_changed();
}
@@ -973,7 +990,12 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
window_pos = cursor_pos;
}
- _text_changed();
+ if (!text_changed_dirty) {
+ if (is_inside_tree()) {
+ MessageQueue::get_singleton()->push_call(this, "_text_changed");
+ }
+ text_changed_dirty = true;
+ }
}
void LineEdit::set_text(String p_text) {
@@ -983,7 +1005,6 @@ void LineEdit::set_text(String p_text) {
update();
cursor_pos = 0;
window_pos = 0;
- _text_changed();
}
void LineEdit::clear() {
@@ -1000,6 +1021,15 @@ String LineEdit::get_text() const {
void LineEdit::set_placeholder(String p_text) {
placeholder = tr(p_text);
+ if ((max_length <= 0) || (placeholder.length() <= max_length)) {
+ Ref<Font> font = get_font("font");
+ cached_placeholder_width = 0;
+ if (font != NULL) {
+ for (int i = 0; i < placeholder.length(); i++) {
+ cached_placeholder_width += font->get_char_size(placeholder[i]).width;
+ }
+ }
+ }
update();
}
@@ -1143,7 +1173,7 @@ Size2 LineEdit::get_minimum_size() const {
/* selection */
-void LineEdit::selection_clear() {
+void LineEdit::deselect() {
selection.begin = 0;
selection.end = 0;
@@ -1159,7 +1189,7 @@ void LineEdit::selection_delete() {
if (selection.enabled)
delete_text(selection.begin, selection.end);
- selection_clear();
+ deselect();
}
void LineEdit::set_max_length(int p_max_length) {
@@ -1200,6 +1230,7 @@ void LineEdit::select_all() {
selection.enabled = true;
update();
}
+
void LineEdit::set_editable(bool p_editable) {
editable = p_editable;
@@ -1216,15 +1247,31 @@ void LineEdit::set_secret(bool p_secret) {
pass = p_secret;
update();
}
+
bool LineEdit::is_secret() const {
return pass;
}
+void LineEdit::set_secret_character(const String &p_string) {
+
+ // An empty string as the secret character would crash the engine
+ // It also wouldn't make sense to use multiple characters as the secret character
+ ERR_EXPLAIN("Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)");
+ ERR_FAIL_COND(p_string.length() != 1);
+
+ secret_character = p_string;
+ update();
+}
+
+String LineEdit::get_secret_character() const {
+ return secret_character;
+}
+
void LineEdit::select(int p_from, int p_to) {
if (p_from == 0 && p_to == 0) {
- selection_clear();
+ deselect();
return;
}
@@ -1302,12 +1349,12 @@ PopupMenu *LineEdit::get_menu() const {
return menu;
}
-#ifdef TOOLS_ENABLED
void LineEdit::_editor_settings_changed() {
+#ifdef TOOLS_ENABLED
cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
-}
#endif
+}
void LineEdit::set_expand_to_text_length(bool p_enabled) {
@@ -1340,6 +1387,7 @@ void LineEdit::_text_changed() {
void LineEdit::_emit_text_change() {
emit_signal("text_changed", text);
_change_notify("text");
+ text_changed_dirty = false;
}
void LineEdit::_clear_redo() {
@@ -1372,18 +1420,19 @@ void LineEdit::_create_undo_state() {
void LineEdit::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed);
ClassDB::bind_method(D_METHOD("_toggle_draw_caret"), &LineEdit::_toggle_draw_caret);
-#ifdef TOOLS_ENABLED
ClassDB::bind_method("_editor_settings_changed", &LineEdit::_editor_settings_changed);
-#endif
ClassDB::bind_method(D_METHOD("set_align", "align"), &LineEdit::set_align);
ClassDB::bind_method(D_METHOD("get_align"), &LineEdit::get_align);
ClassDB::bind_method(D_METHOD("_gui_input"), &LineEdit::_gui_input);
ClassDB::bind_method(D_METHOD("clear"), &LineEdit::clear);
+ ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all);
+ ClassDB::bind_method(D_METHOD("deselect"), &LineEdit::deselect);
ClassDB::bind_method(D_METHOD("set_text", "text"), &LineEdit::set_text);
ClassDB::bind_method(D_METHOD("get_text"), &LineEdit::get_text);
ClassDB::bind_method(D_METHOD("set_placeholder", "text"), &LineEdit::set_placeholder);
@@ -1405,14 +1454,15 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_editable"), &LineEdit::is_editable);
ClassDB::bind_method(D_METHOD("set_secret", "enabled"), &LineEdit::set_secret);
ClassDB::bind_method(D_METHOD("is_secret"), &LineEdit::is_secret);
- ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("set_secret_character", "character"), &LineEdit::set_secret_character);
+ ClassDB::bind_method(D_METHOD("get_secret_character"), &LineEdit::get_secret_character);
ClassDB::bind_method(D_METHOD("menu_option", "option"), &LineEdit::menu_option);
ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled);
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled);
- ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "text")));
- ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "text")));
+ ADD_SIGNAL(MethodInfo("text_changed", PropertyInfo(Variant::STRING, "new_text")));
+ ADD_SIGNAL(MethodInfo("text_entered", PropertyInfo(Variant::STRING, "new_text")));
BIND_ENUM_CONSTANT(ALIGN_LEFT);
BIND_ENUM_CONSTANT(ALIGN_CENTER);
@@ -1433,15 +1483,17 @@ void LineEdit::_bind_methods() {
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "max_length"), "set_max_length", "get_max_length");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character");
ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length");
ADD_PROPERTY(PropertyInfo(Variant::INT, "focus_mode", PROPERTY_HINT_ENUM, "None,Click,All"), "set_focus_mode", "get_focus_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
ADD_GROUP("Placeholder", "placeholder_");
ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position");
}
LineEdit::LineEdit() {
@@ -1450,14 +1502,17 @@ LineEdit::LineEdit() {
_create_undo_state();
align = ALIGN_LEFT;
cached_width = 0;
+ cached_placeholder_width = 0;
cursor_pos = 0;
window_pos = 0;
window_has_focus = true;
max_length = 0;
pass = false;
+ secret_character = "*";
+ text_changed_dirty = false;
placeholder_alpha = 0.6;
- selection_clear();
+ deselect();
set_focus_mode(FOCUS_ALL);
editable = true;
set_default_cursor_shape(CURSOR_IBEAM);
@@ -1474,15 +1529,15 @@ LineEdit::LineEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- menu->add_item(TTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- menu->add_item(TTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- menu->add_item(TTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
+ menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
menu->add_separator();
- menu->add_item(TTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
- menu->add_item(TTR("Clear"), MENU_CLEAR);
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+ menu->add_item(RTR("Clear"), MENU_CLEAR);
menu->add_separator();
- menu->add_item(TTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
- menu->add_item(TTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
+ menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Redo"), MENU_REDO, KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z);
menu->connect("id_pressed", this, "menu_option");
expand_to_text_length = false;
}
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index c3a299c2f5..e9314ba8dd 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LINE_EDIT_H
#define LINE_EDIT_H
@@ -66,10 +67,12 @@ private:
bool editable;
bool pass;
+ bool text_changed_dirty;
String undo_text;
String text;
String placeholder;
+ String secret_character;
float placeholder_alpha;
String ime_text;
Point2 ime_selection;
@@ -82,6 +85,7 @@ private:
int max_length; // 0 for no maximum
int cached_width;
+ int cached_placeholder_width;
struct Selection {
@@ -119,9 +123,7 @@ private:
void shift_selection_check_pre(bool);
void shift_selection_check_post(bool);
- void selection_clear();
void selection_fill_at_cursor();
- void selection_delete();
void set_window_pos(int p_pos);
void set_cursor_at_pixel_pos(int p_x);
@@ -132,9 +134,7 @@ private:
void clear_internal();
void changed_internal();
-#ifdef TOOLS_ENABLED
void _editor_settings_changed();
-#endif
void _gui_input(Ref<InputEvent> p_event);
void _notification(int p_what);
@@ -155,7 +155,10 @@ public:
bool is_context_menu_enabled();
PopupMenu *get_menu() const;
+ void select(int p_from = 0, int p_to = -1);
void select_all();
+ void selection_delete();
+ void deselect();
void delete_char();
void delete_text(int p_from_column, int p_to_column);
@@ -190,7 +193,8 @@ public:
void set_secret(bool p_secret);
bool is_secret() const;
- void select(int p_from = 0, int p_to = -1);
+ void set_secret_character(const String &p_string);
+ String get_secret_character() const;
virtual Size2 get_minimum_size() const;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index 9fe94fc464..d862e8669c 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "link_button.h"
void LinkButton::set_text(const String &p_text) {
diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h
index 386eb452ae..0821ad9c0d 100644
--- a/scene/gui/link_button.h
+++ b/scene/gui/link_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef LINKBUTTON_H
#define LINKBUTTON_H
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index 14991f5d44..5e1d53fe1d 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "margin_container.h"
Size2 MarginContainer::get_minimum_size() const {
diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h
index 9703d9ebe0..ea75109248 100644
--- a/scene/gui/margin_container.h
+++ b/scene/gui/margin_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MARGIN_CONTAINER_H
#define MARGIN_CONTAINER_H
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index d850553957..87cf4dc334 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,12 +27,16 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "menu_button.h"
#include "os/keyboard.h"
#include "scene/main/viewport.h"
void MenuButton::_unhandled_key_input(Ref<InputEvent> p_event) {
+ if (disable_shortcuts)
+ return;
+
if (p_event->is_pressed() && !p_event->is_echo() && (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventAction>(*p_event))) {
if (!get_parent() || !is_visible_in_tree() || is_disabled())
@@ -55,30 +59,14 @@ void MenuButton::pressed() {
popup->set_size(Size2(size.width, 0));
popup->set_parent_rect(Rect2(Point2(gp - popup->get_global_position()), get_size()));
popup->popup();
- popup->set_invalidate_click_until_motion();
}
void MenuButton::_gui_input(Ref<InputEvent> p_event) {
- /*if (p_event.type==InputEvent::MOUSE_BUTTON && p_event->get_button_index()==BUTTON_LEFT) {
- clicked=p_event->is_pressed();
- }
- if (clicked && p_event.type==InputEvent::MOUSE_MOTION && popup->is_visible_in_tree()) {
-
- Point2 gt = Point2(p_event.mouse_motion.x,p_event.mouse_motion.y);
- gt = get_global_transform().xform(gt);
- Point2 lt = popup->get_transform().affine_inverse().xform(gt);
- if (popup->has_point(lt)) {
- //print_line("HAS POINT!!!");
- popup->call_deferred("grab_click_focus");
- }
-
- }*/
-
BaseButton::_gui_input(p_event);
}
-PopupMenu *MenuButton::get_popup() {
+PopupMenu *MenuButton::get_popup() const {
return popup;
}
@@ -98,21 +86,28 @@ void MenuButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &MenuButton::_unhandled_key_input);
ClassDB::bind_method(D_METHOD("_set_items"), &MenuButton::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &MenuButton::_get_items);
+ ClassDB::bind_method(D_METHOD("set_disable_shortcuts", "disabled"), &MenuButton::set_disable_shortcuts);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
ADD_SIGNAL(MethodInfo("about_to_show"));
}
+
+void MenuButton::set_disable_shortcuts(bool p_disabled) {
+
+ disable_shortcuts = p_disabled;
+}
+
MenuButton::MenuButton() {
set_flat(true);
+ set_disable_shortcuts(false);
set_enabled_focus_mode(FOCUS_NONE);
popup = memnew(PopupMenu);
popup->hide();
add_child(popup);
popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
- connect("button_up", popup, "call_deferred", make_binds("grab_click_focus"));
set_process_unhandled_key_input(true);
set_action_mode(ACTION_MODE_BUTTON_PRESS);
}
diff --git a/scene/gui/menu_button.h b/scene/gui/menu_button.h
index c7f1d976ff..2356444ecb 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MENU_BUTTON_H
#define MENU_BUTTON_H
@@ -40,6 +41,7 @@ class MenuButton : public Button {
GDCLASS(MenuButton, Button);
bool clicked;
+ bool disable_shortcuts;
PopupMenu *popup;
virtual void pressed();
@@ -53,7 +55,9 @@ protected:
static void _bind_methods();
public:
- PopupMenu *get_popup();
+ PopupMenu *get_popup() const;
+ void set_disable_shortcuts(bool p_disabled);
+
MenuButton();
~MenuButton();
};
diff --git a/scene/gui/nine_patch_rect.cpp b/scene/gui/nine_patch_rect.cpp
index c02d80bba8..b8f6ffe6d2 100644
--- a/scene/gui/nine_patch_rect.cpp
+++ b/scene/gui/nine_patch_rect.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "nine_patch_rect.h"
#include "servers/visual_server.h"
diff --git a/scene/gui/nine_patch_rect.h b/scene/gui/nine_patch_rect.h
index 809daf9db3..b4b4602a7d 100644
--- a/scene/gui/nine_patch_rect.h
+++ b/scene/gui/nine_patch_rect.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NINE_PATCH_RECT_H
#define NINE_PATCH_RECT_H
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 70f3d9ca83..c5e4149782 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "option_button.h"
#include "print_string.h"
@@ -42,41 +43,42 @@ Size2 OptionButton::get_minimum_size() const {
void OptionButton::_notification(int p_what) {
- switch (p_what) {
-
- case NOTIFICATION_DRAW: {
-
- if (!has_icon("arrow"))
- return;
-
- RID ci = get_canvas_item();
- Ref<Texture> arrow = Control::get_icon("arrow");
- Ref<StyleBox> normal = get_stylebox("normal");
- Color clr = Color(1, 1, 1);
- if (get_constant("modulate_arrow"))
- switch (get_draw_mode()) {
- case DRAW_PRESSED:
- clr = get_color("font_color_pressed");
- break;
- case DRAW_HOVER:
- clr = get_color("font_color_hover");
- break;
- case DRAW_DISABLED:
- clr = get_color("font_color_disabled");
- break;
- default:
- clr = get_color("font_color");
- }
-
- Size2 size = get_size();
-
- Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2)));
- arrow->draw(ci, ofs, clr);
-
- } break;
+ if (p_what == NOTIFICATION_DRAW) {
+
+ if (!has_icon("arrow"))
+ return;
+
+ RID ci = get_canvas_item();
+ Ref<Texture> arrow = Control::get_icon("arrow");
+ Ref<StyleBox> normal = get_stylebox("normal");
+ Color clr = Color(1, 1, 1);
+ if (get_constant("modulate_arrow")) {
+ switch (get_draw_mode()) {
+ case DRAW_PRESSED:
+ clr = get_color("font_color_pressed");
+ break;
+ case DRAW_HOVER:
+ clr = get_color("font_color_hover");
+ break;
+ case DRAW_DISABLED:
+ clr = get_color("font_color_disabled");
+ break;
+ default:
+ clr = get_color("font_color");
+ }
+ }
+
+ Size2 size = get_size();
+
+ Point2 ofs(size.width - arrow->get_width() - get_constant("arrow_margin"), int(Math::abs((size.height - arrow->get_height()) / 2)));
+ arrow->draw(ci, ofs, clr);
}
}
+void OptionButton::_focused(int p_which) {
+ emit_signal("item_focused", p_which);
+}
+
void OptionButton::_selected(int p_which) {
int selid = -1;
@@ -110,13 +112,13 @@ void OptionButton::pressed() {
void OptionButton::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID) {
- popup->add_icon_check_item(p_icon, p_label, p_ID);
+ popup->add_icon_radio_check_item(p_icon, p_label, p_ID);
if (popup->get_item_count() == 1)
select(0);
}
void OptionButton::add_item(const String &p_label, int p_ID) {
- popup->add_check_item(p_label, p_ID);
+ popup->add_radio_check_item(p_label, p_ID);
if (popup->get_item_count() == 1)
select(0);
}
@@ -244,6 +246,11 @@ void OptionButton::remove_item(int p_idx) {
popup->remove_item(p_idx);
}
+PopupMenu *OptionButton::get_popup() const {
+
+ return popup;
+}
+
Array OptionButton::_get_items() const {
Array items;
@@ -287,9 +294,10 @@ void OptionButton::get_translatable_strings(List<String> *p_strings) const {
void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("_selected"), &OptionButton::_selected);
+ ClassDB::bind_method(D_METHOD("_focused"), &OptionButton::_focused);
ClassDB::bind_method(D_METHOD("add_item", "label", "id"), &OptionButton::add_item, DEFVAL(-1));
- ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id"), &OptionButton::add_icon_item);
+ ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id"), &OptionButton::add_icon_item, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &OptionButton::set_item_text);
ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "texture"), &OptionButton::set_item_icon);
ClassDB::bind_method(D_METHOD("set_item_disabled", "idx", "disabled"), &OptionButton::set_item_disabled);
@@ -310,25 +318,31 @@ void OptionButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_item", "idx"), &OptionButton::remove_item);
ClassDB::bind_method(D_METHOD("_select_int"), &OptionButton::_select_int);
+ ClassDB::bind_method(D_METHOD("get_popup"), &OptionButton::get_popup);
+
ClassDB::bind_method(D_METHOD("_set_items"), &OptionButton::_set_items);
ClassDB::bind_method(D_METHOD("_get_items"), &OptionButton::_get_items);
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
+ // "selected" property must come after "items", otherwise GH-10213 occurs
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items");
ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "ID")));
+ ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "ID")));
}
OptionButton::OptionButton() {
+ current = -1;
+ set_text_align(ALIGN_LEFT);
+ set_action_mode(ACTION_MODE_BUTTON_PRESS);
+
popup = memnew(PopupMenu);
popup->hide();
+ add_child(popup);
popup->set_as_toplevel(true);
popup->set_pass_on_modal_close_click(false);
- add_child(popup);
popup->connect("id_pressed", this, "_selected");
-
- current = -1;
- set_text_align(ALIGN_LEFT);
+ popup->connect("id_focused", this, "_focused");
}
OptionButton::~OptionButton() {
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index a06c540678..d5f866d806 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef OPTION_BUTTON_H
#define OPTION_BUTTON_H
@@ -42,6 +43,7 @@ class OptionButton : public Button {
PopupMenu *popup;
int current;
+ void _focused(int p_which);
void _selected(int p_which);
void _select(int p_which, bool p_emit = false);
void _select_int(int p_which);
@@ -85,6 +87,8 @@ public:
void remove_item(int p_idx);
+ PopupMenu *get_popup() const;
+
virtual void get_translatable_strings(List<String> *p_strings) const;
OptionButton();
diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp
index 536b655f75..4375e03a50 100644
--- a/scene/gui/panel.cpp
+++ b/scene/gui/panel.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "panel.h"
#include "print_string.h"
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index cc7ca47319..db8b35372e 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PANEL_H
#define PANEL_H
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index a0c75d1330..a778d62659 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "panel_container.h"
Size2 PanelContainer::get_minimum_size() const {
diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h
index 5d8f1ee64b..267e2b921f 100644
--- a/scene/gui/panel_container.h
+++ b/scene/gui/panel_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PANEL_CONTAINER_H
#define PANEL_CONTAINER_H
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 2110298950..d18a3a3f2f 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "popup.h"
#include "engine.h"
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index 6739c580f2..550e803578 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef POPUP_H
#define POPUP_H
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 32f889e826..93865cebde 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "popup_menu.h"
#include "os/input.h"
#include "os/keyboard.h"
@@ -42,24 +43,6 @@ String PopupMenu::_get_accel_text(int p_item) const {
else if (items[p_item].accel)
return keycode_get_string(items[p_item].accel);
return String();
-
- /*
- String atxt;
- if (p_accel&KEY_MASK_SHIFT)
- atxt+="Shift+";
- if (p_accel&KEY_MASK_ALT)
- atxt+="Alt+";
- if (p_accel&KEY_MASK_CTRL)
- atxt+="Ctrl+";
- if (p_accel&KEY_MASK_META)
- atxt+="Meta+";
-
- p_accel&=KEY_CODE_MASK;
-
- atxt+=String::chr(p_accel).to_upper();
-
- return atxt;
-*/
}
Size2 PopupMenu::get_minimum_size() const {
@@ -72,7 +55,7 @@ Size2 PopupMenu::get_minimum_size() const {
float max_w = 0;
int font_h = font->get_height();
- int check_w = get_icon("checked")->get_width();
+ int check_w = MAX(get_icon("checked")->get_width(), get_icon("radio_checked")->get_width());
int accel_max_w = 0;
for (int i = 0; i < items.size(); i++) {
@@ -91,7 +74,7 @@ Size2 PopupMenu::get_minimum_size() const {
size.width += items[i].h_ofs;
- if (items[i].checkable) {
+ if (items[i].checkable_type) {
size.width += check_w + hseparation;
}
@@ -136,13 +119,11 @@ int PopupMenu::_get_mouse_over(const Point2 &p_over) const {
Ref<Font> font = get_font("font");
int vseparation = get_constant("vseparation");
- //int hseparation = get_constant("hseparation");
float font_h = font->get_height();
for (int i = 0; i < items.size(); i++) {
- if (i > 0)
- ofs.y += vseparation;
+ ofs.y += vseparation;
float h;
if (!items[i].icon.is_null()) {
@@ -208,55 +189,91 @@ void PopupMenu::_submenu_timeout() {
submenu_over = -1;
}
+void PopupMenu::_scroll(float p_factor, const Point2 &p_over) {
+
+ const float global_y = get_global_position().y;
+
+ int vseparation = get_constant("vseparation");
+ Ref<Font> font = get_font("font");
+
+ float dy = (vseparation + font->get_height()) * 3 * p_factor;
+ if (dy > 0 && global_y < 0)
+ dy = MIN(dy, -global_y - 1);
+ else if (dy < 0 && global_y + get_size().y > get_viewport_rect().size.y)
+ dy = -MIN(-dy, global_y + get_size().y - get_viewport_rect().size.y - 1);
+ set_position(get_position() + Vector2(0, dy));
+
+ Ref<InputEventMouseMotion> ie;
+ ie.instance();
+ ie->set_position(p_over - Vector2(0, dy));
+ _gui_input(ie);
+}
+
void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
- Ref<InputEventKey> k = p_event;
+ if (p_event->is_action("ui_down") && p_event->is_pressed()) {
- if (k.is_valid()) {
+ int search_from = mouse_over + 1;
+ if (search_from >= items.size())
+ search_from = 0;
- if (!k->is_pressed())
- return;
+ for (int i = search_from; i < items.size(); i++) {
- switch (k->get_scancode()) {
+ if (i < 0 || i >= items.size())
+ continue;
- case KEY_DOWN: {
+ if (!items[i].separator && !items[i].disabled) {
- for (int i = mouse_over + 1; i < items.size(); i++) {
+ mouse_over = i;
+ emit_signal("id_focused", i);
+ update();
+ accept_event();
+ break;
+ }
+ }
+ } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
- if (i < 0 || i >= items.size())
- continue;
+ int search_from = mouse_over - 1;
+ if (search_from < 0)
+ search_from = items.size() - 1;
- if (!items[i].separator && !items[i].disabled) {
+ for (int i = search_from; i >= 0; i--) {
- mouse_over = i;
- update();
- break;
- }
- }
- } break;
- case KEY_UP: {
+ if (i < 0 || i >= items.size())
+ continue;
- for (int i = mouse_over - 1; i >= 0; i--) {
+ if (!items[i].separator && !items[i].disabled) {
- if (i < 0 || i >= items.size())
- continue;
+ mouse_over = i;
+ emit_signal("id_focused", i);
+ update();
+ accept_event();
+ break;
+ }
+ }
+ } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
- if (!items[i].separator && !items[i].disabled) {
+ Node *n = get_parent();
+ if (n && Object::cast_to<PopupMenu>(n)) {
+ hide();
+ accept_event();
+ }
+ } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
- mouse_over = i;
- update();
- break;
- }
- }
- } break;
- case KEY_ENTER:
- case KEY_KP_ENTER: {
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+ _activate_submenu(mouse_over);
+ accept_event();
+ }
+ } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
- if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
- activate_item(mouse_over);
- }
- } break;
+ if (items[mouse_over].submenu != "" && submenu_over != mouse_over) {
+ _activate_submenu(mouse_over);
+ } else {
+ activate_item(mouse_over);
+ }
+ accept_event();
}
}
@@ -267,70 +284,52 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
if (b->is_pressed())
return;
- switch (b->get_button_index()) {
+ int button_idx = b->get_button_index();
+ switch (button_idx) {
case BUTTON_WHEEL_DOWN: {
if (get_global_position().y + get_size().y > get_viewport_rect().size.y) {
-
- int vseparation = get_constant("vseparation");
- Ref<Font> font = get_font("font");
-
- Point2 pos = get_position();
- int s = (vseparation + font->get_height()) * 3;
- pos.y -= (s * b->get_factor());
- set_position(pos);
-
- //update hover
- Ref<InputEventMouseMotion> ie;
- ie.instance();
- ie->set_position(b->get_position() + Vector2(0, s));
- _gui_input(ie);
+ _scroll(-b->get_factor(), b->get_position());
}
} break;
case BUTTON_WHEEL_UP: {
if (get_global_position().y < 0) {
-
- int vseparation = get_constant("vseparation");
- Ref<Font> font = get_font("font");
-
- Point2 pos = get_position();
- int s = (vseparation + font->get_height()) * 3;
- pos.y += (s * b->get_factor());
- set_position(pos);
-
- //update hover
- Ref<InputEventMouseMotion> ie;
- ie.instance();
- ie->set_position(b->get_position() - Vector2(0, s));
- _gui_input(ie);
+ _scroll(b->get_factor(), b->get_position());
}
} break;
- case BUTTON_LEFT: {
+ default: {
+ // Allow activating item by releasing the LMB or any that was down when the popup appeared
+ if (button_idx == BUTTON_LEFT || (initial_button_mask & (1 << (button_idx - 1)))) {
- int over = _get_mouse_over(b->get_position());
+ bool was_during_grabbed_click = during_grabbed_click;
+ during_grabbed_click = false;
- if (invalidated_click) {
- invalidated_click = false;
- break;
- }
- if (over < 0) {
- hide();
- break; //non-activable
- }
+ int over = _get_mouse_over(b->get_position());
- if (items[over].separator || items[over].disabled)
- break;
+ if (invalidated_click) {
+ invalidated_click = false;
+ break;
+ }
+ if (over < 0) {
+ if (!was_during_grabbed_click) {
+ hide();
+ }
+ break; //non-activable
+ }
- if (items[over].submenu != "") {
+ if (items[over].separator || items[over].disabled)
+ break;
- _activate_submenu(over);
- return;
- }
- activate_item(over);
+ if (items[over].submenu != "") {
- } break;
+ _activate_submenu(over);
+ return;
+ }
+ activate_item(over);
+ }
+ }
}
//update();
@@ -373,6 +372,13 @@ void PopupMenu::_gui_input(const Ref<InputEvent> &p_event) {
update();
}
}
+
+ Ref<InputEventPanGesture> pan_gesture = p_event;
+ if (pan_gesture.is_valid()) {
+ if (get_global_position().y + get_size().y > get_viewport_rect().size.y || get_global_position().y < 0) {
+ _scroll(-pan_gesture->get_delta().y, pan_gesture->get_position());
+ }
+ }
}
bool PopupMenu::has_point(const Point2 &p_point) const {
@@ -410,8 +416,9 @@ void PopupMenu::_notification(int p_what) {
Ref<StyleBox> style = get_stylebox("panel");
Ref<StyleBox> hover = get_stylebox("hover");
Ref<Font> font = get_font("font");
- Ref<Texture> check = get_icon("checked");
- Ref<Texture> uncheck = get_icon("unchecked");
+ // In Item::checkable_type enum order (less the non-checkable member)
+ Ref<Texture> check[] = { get_icon("checked"), get_icon("radio_checked") };
+ Ref<Texture> uncheck[] = { get_icon("unchecked"), get_icon("radio_unchecked") };
Ref<Texture> submenu = get_icon("submenu");
Ref<StyleBox> separator = get_stylebox("separator");
@@ -445,7 +452,7 @@ void PopupMenu::_notification(int p_what) {
if (i == mouse_over) {
- hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation * 2)));
+ hover->draw(ci, Rect2(item_ofs + Point2(-hseparation, -vseparation / 2), Size2(get_size().width - style->get_minimum_size().width + hseparation * 2, h + vseparation)));
}
if (items[i].separator) {
@@ -454,14 +461,10 @@ void PopupMenu::_notification(int p_what) {
separator->draw(ci, Rect2(item_ofs + Point2(0, Math::floor((h - sep_h) / 2.0)), Size2(get_size().width - style->get_minimum_size().width, sep_h)));
}
- if (items[i].checkable) {
-
- if (items[i].checked)
- check->draw(ci, item_ofs + Point2(0, Math::floor((h - check->get_height()) / 2.0)));
- else
- uncheck->draw(ci, item_ofs + Point2(0, Math::floor((h - check->get_height()) / 2.0)));
-
- item_ofs.x += check->get_width() + hseparation;
+ if (items[i].checkable_type) {
+ Texture *icon = (items[i].checked ? check[items[i].checkable_type - 1] : uncheck[items[i].checkable_type - 1]).ptr();
+ icon->draw(ci, item_ofs + Point2(0, Math::floor((h - icon->get_height()) / 2.0)));
+ item_ofs.x += icon->get_width() + hseparation;
}
if (!items[i].icon.is_null()) {
@@ -500,6 +503,18 @@ void PopupMenu::_notification(int p_what) {
} break;
case NOTIFICATION_MOUSE_EXIT: {
+ if (mouse_over >= 0 && (items[mouse_over].submenu == "" || submenu_over != -1)) {
+ mouse_over = -1;
+ update();
+ }
+ } break;
+ case NOTIFICATION_POST_POPUP: {
+
+ initial_button_mask = Input::get_singleton()->get_mouse_button_mask();
+ during_grabbed_click = (bool)initial_button_mask;
+ } break;
+ case NOTIFICATION_POPUP_HIDE: {
+
if (mouse_over >= 0) {
mouse_over = -1;
update();
@@ -518,6 +533,7 @@ void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label,
item.ID = p_ID;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) {
@@ -528,6 +544,7 @@ void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) {
item.ID = p_ID;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_ID) {
@@ -539,6 +556,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu,
item.submenu = p_submenu;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) {
@@ -549,10 +567,12 @@ void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_
item.xl_text = tr(p_label);
item.accel = p_accel;
item.ID = p_ID;
- item.checkable = true;
+ item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
+ minimum_size_changed();
}
+
void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel) {
Item item;
@@ -560,9 +580,26 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel
item.xl_text = tr(p_label);
item.accel = p_accel;
item.ID = p_ID;
- item.checkable = true;
+ item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
+ minimum_size_changed();
+}
+
+void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p_accel) {
+
+ add_check_item(p_label, p_ID, p_accel);
+ items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ update();
+ minimum_size_changed();
+}
+
+void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) {
+
+ add_icon_check_item(p_icon, p_label, p_ID, p_accel);
+ items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ update();
+ minimum_size_changed();
}
void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -578,6 +615,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut
item.shortcut_is_global = p_global;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -592,7 +630,9 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_g
item.shortcut_is_global = p_global;
items.push_back(item);
update();
+ minimum_size_changed();
}
+
void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
ERR_FAIL_COND(p_shortcut.is_null());
@@ -602,11 +642,12 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<Sh
Item item;
item.ID = p_ID;
item.shortcut = p_shortcut;
- item.checkable = true;
+ item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
item.icon = p_icon;
item.shortcut_is_global = p_global;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
@@ -619,9 +660,18 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo
item.ID = p_ID;
item.shortcut = p_shortcut;
item.shortcut_is_global = p_global;
- item.checkable = true;
+ item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX;
items.push_back(item);
update();
+ minimum_size_changed();
+}
+
+void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) {
+
+ add_check_shortcut(p_shortcut, p_ID, p_global);
+ items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON;
+ update();
+ minimum_size_changed();
}
void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) {
@@ -631,11 +681,11 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int
item.xl_text = tr(p_label);
item.accel = p_accel;
item.ID = p_ID;
- item.checkable = false;
item.max_states = p_max_states;
item.state = p_default_state;
items.push_back(item);
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_text(int p_idx, const String &p_text) {
@@ -645,6 +695,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) {
items[p_idx].xl_text = tr(p_text);
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
@@ -652,6 +703,7 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) {
items[p_idx].icon = p_icon;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
@@ -660,6 +712,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) {
items[p_idx].checked = p_checked;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_id(int p_idx, int p_ID) {
@@ -667,6 +720,7 @@ void PopupMenu::set_item_id(int p_idx, int p_ID) {
items[p_idx].ID = p_ID;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
@@ -675,6 +729,7 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) {
items[p_idx].accel = p_accel;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
@@ -682,6 +737,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].metadata = p_meta;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
@@ -689,6 +745,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].disabled = p_disabled;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
@@ -696,6 +753,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].submenu = p_submenu;
update();
+ minimum_size_changed();
}
void PopupMenu::toggle_item_checked(int p_idx) {
@@ -703,6 +761,7 @@ void PopupMenu::toggle_item_checked(int p_idx) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].checked = !items[p_idx].checked;
update();
+ minimum_size_changed();
}
String PopupMenu::get_item_text(int p_idx) const {
@@ -806,7 +865,14 @@ bool PopupMenu::is_item_separator(int p_idx) const {
void PopupMenu::set_item_as_checkable(int p_idx, bool p_checkable) {
ERR_FAIL_INDEX(p_idx, items.size());
- items[p_idx].checkable = p_checkable;
+ items[p_idx].checkable_type = p_checkable ? Item::CHECKABLE_TYPE_CHECK_BOX : Item::CHECKABLE_TYPE_NONE;
+ update();
+}
+
+void PopupMenu::set_item_as_radio_checkable(int p_idx, bool p_radio_checkable) {
+
+ ERR_FAIL_INDEX(p_idx, items.size());
+ items[p_idx].checkable_type = p_radio_checkable ? Item::CHECKABLE_TYPE_RADIO_BUTTON : Item::CHECKABLE_TYPE_NONE;
update();
}
@@ -837,6 +903,7 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) {
ERR_FAIL_INDEX(p_idx, items.size());
items[p_idx].h_ofs = p_offset;
update();
+ minimum_size_changed();
}
void PopupMenu::set_item_multistate(int p_idx, int p_state) {
@@ -862,7 +929,12 @@ void PopupMenu::toggle_item_multistate(int p_idx) {
bool PopupMenu::is_item_checkable(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, items.size(), false);
- return items[p_idx].checkable;
+ return items[p_idx].checkable_type;
+}
+
+bool PopupMenu::is_item_radio_checkable(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, items.size(), false);
+ return items[p_idx].checkable_type == Item::CHECKABLE_TYPE_RADIO_BUTTON;
}
int PopupMenu::get_item_count() const {
@@ -936,7 +1008,7 @@ void PopupMenu::activate_item(int p_item) {
// We close all parents that are chained together,
// with hide_on_item_selection enabled
- if (items[p_item].checkable) {
+ if (items[p_item].checkable_type) {
if (!hide_on_checkable_item_selection || !pop->is_hide_on_checkable_item_selection())
break;
} else if (0 < items[p_item].max_states) {
@@ -953,7 +1025,7 @@ void PopupMenu::activate_item(int p_item) {
// Hides popup by default; unless otherwise specified
// by using set_hide_on_item_selection and set_hide_on_checkable_item_selection
- if (items[p_item].checkable) {
+ if (items[p_item].checkable_type) {
if (!hide_on_checkable_item_selection)
return;
} else if (0 < items[p_item].max_states) {
@@ -996,6 +1068,7 @@ void PopupMenu::clear() {
items.clear();
mouse_over = -1;
update();
+ minimum_size_changed();
}
Array PopupMenu::_get_items() const {
@@ -1005,7 +1078,9 @@ Array PopupMenu::_get_items() const {
items.push_back(get_item_text(i));
items.push_back(get_item_icon(i));
- items.push_back(is_item_checkable(i));
+ // For compatibility, use false/true for no/checkbox and integers for other values
+ int ct = this->items[i].checkable_type;
+ items.push_back(Variant(ct <= Item::CHECKABLE_TYPE_CHECK_BOX ? is_item_checkable(i) : ct));
items.push_back(is_item_checked(i));
items.push_back(is_item_disabled(i));
@@ -1048,7 +1123,9 @@ void PopupMenu::_set_items(const Array &p_items) {
String text = p_items[i + 0];
Ref<Texture> icon = p_items[i + 1];
+ // For compatibility, use false/true for no/checkbox and integers for other values
bool checkable = p_items[i + 2];
+ bool radio_checkable = (int)p_items[i + 2] == Item::CHECKABLE_TYPE_RADIO_BUTTON;
bool checked = p_items[i + 3];
bool disabled = p_items[i + 4];
@@ -1061,7 +1138,13 @@ void PopupMenu::_set_items(const Array &p_items) {
int idx = get_item_count();
add_item(text, id);
set_item_icon(idx, icon);
- set_item_as_checkable(idx, checkable);
+ if (checkable) {
+ if (radio_checkable) {
+ set_item_as_radio_checkable(idx, true);
+ } else {
+ set_item_as_checkable(idx, true);
+ }
+ }
set_item_checked(idx, checked);
set_item_disabled(idx, disabled);
set_item_id(idx, id);
@@ -1142,12 +1225,14 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_icon_check_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_check_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_radio_check_item", "label", "id", "accel"), &PopupMenu::add_radio_check_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_submenu_item", "label", "submenu", "id"), &PopupMenu::add_submenu_item, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("add_icon_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_shortcut", "shortcut", "id", "global"), &PopupMenu::add_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_icon_check_shortcut", "texture", "shortcut", "id", "global"), &PopupMenu::add_icon_check_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("add_check_shortcut", "shortcut", "id", "global"), &PopupMenu::add_check_shortcut, DEFVAL(-1), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("add_radio_check_shortcut", "shortcut", "id", "global"), &PopupMenu::add_radio_check_shortcut, DEFVAL(-1), DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_item_text", "idx", "text"), &PopupMenu::set_item_text);
ClassDB::bind_method(D_METHOD("set_item_icon", "idx", "icon"), &PopupMenu::set_item_icon);
@@ -1159,6 +1244,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_item_submenu", "idx", "submenu"), &PopupMenu::set_item_submenu);
ClassDB::bind_method(D_METHOD("set_item_as_separator", "idx", "enable"), &PopupMenu::set_item_as_separator);
ClassDB::bind_method(D_METHOD("set_item_as_checkable", "idx", "enable"), &PopupMenu::set_item_as_checkable);
+ ClassDB::bind_method(D_METHOD("set_item_as_radio_checkable", "idx", "enable"), &PopupMenu::set_item_as_radio_checkable);
ClassDB::bind_method(D_METHOD("set_item_tooltip", "idx", "tooltip"), &PopupMenu::set_item_tooltip);
ClassDB::bind_method(D_METHOD("set_item_shortcut", "idx", "shortcut", "global"), &PopupMenu::set_item_shortcut, DEFVAL(false));
ClassDB::bind_method(D_METHOD("set_item_multistate", "idx", "state"), &PopupMenu::set_item_multistate);
@@ -1177,6 +1263,7 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_item_submenu", "idx"), &PopupMenu::get_item_submenu);
ClassDB::bind_method(D_METHOD("is_item_separator", "idx"), &PopupMenu::is_item_separator);
ClassDB::bind_method(D_METHOD("is_item_checkable", "idx"), &PopupMenu::is_item_checkable);
+ ClassDB::bind_method(D_METHOD("is_item_radio_checkable", "idx"), &PopupMenu::is_item_radio_checkable);
ClassDB::bind_method(D_METHOD("get_item_tooltip", "idx"), &PopupMenu::get_item_tooltip);
ClassDB::bind_method(D_METHOD("get_item_shortcut", "idx"), &PopupMenu::get_item_shortcut);
@@ -1201,22 +1288,30 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("_submenu_timeout"), &PopupMenu::_submenu_timeout);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_items", "_get_items");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_items", "_get_items");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection");
ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection");
+ ADD_PROPERTYNO(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection");
ADD_SIGNAL(MethodInfo("id_pressed", PropertyInfo(Variant::INT, "ID")));
+ ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "ID")));
ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index")));
}
-void PopupMenu::set_invalidate_click_until_motion() {
+void PopupMenu::popup(const Rect2 &p_bounds) {
+
+ grab_click_focus();
moved = Vector2();
invalidated_click = true;
+ Popup::popup(p_bounds);
}
PopupMenu::PopupMenu() {
mouse_over = -1;
+ submenu_over = -1;
+ initial_button_mask = 0;
+ during_grabbed_click = false;
set_focus_mode(FOCUS_ALL);
set_as_toplevel(true);
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index ee514f4c4b..fde91bd845 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef POPUP_MENU_H
#define POPUP_MENU_H
@@ -45,7 +46,11 @@ class PopupMenu : public Popup {
String text;
String xl_text;
bool checked;
- bool checkable;
+ enum {
+ CHECKABLE_TYPE_NONE,
+ CHECKABLE_TYPE_CHECK_BOX,
+ CHECKABLE_TYPE_RADIO_BUTTON,
+ } checkable_type;
int max_states;
int state;
bool separator;
@@ -62,7 +67,7 @@ class PopupMenu : public Popup {
Item() {
checked = false;
- checkable = false;
+ checkable_type = CHECKABLE_TYPE_NONE;
separator = false;
max_states = 0;
state = 0;
@@ -77,12 +82,15 @@ class PopupMenu : public Popup {
Timer *submenu_timer;
List<Rect2> autohide_areas;
Vector<Item> items;
+ int initial_button_mask;
+ bool during_grabbed_click;
int mouse_over;
int submenu_over;
Rect2 parent_rect;
String _get_accel_text(int p_item) const;
int _get_mouse_over(const Point2 &p_over) const;
virtual Size2 get_minimum_size() const;
+ void _scroll(float p_factor, const Point2 &p_over);
void _gui_input(const Ref<InputEvent> &p_event);
void _activate_submenu(int over);
void _submenu_timeout();
@@ -113,12 +121,15 @@ public:
void add_item(const String &p_label, int p_ID = -1, uint32_t p_accel = 0);
void add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID = -1, uint32_t p_accel = 0);
void add_check_item(const String &p_label, int p_ID = -1, uint32_t p_accel = 0);
+ void add_radio_check_item(const String &p_label, int p_ID = -1, uint32_t p_accel = 0);
+ void add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID = -1, uint32_t p_accel = 0);
void add_submenu_item(const String &p_label, const String &p_submenu, int p_ID = -1);
void add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
void add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
void add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
void add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
+ void add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID = -1, bool p_global = false);
void add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID = -1, uint32_t p_accel = 0);
@@ -132,6 +143,7 @@ public:
void set_item_submenu(int p_idx, const String &p_submenu);
void set_item_as_separator(int p_idx, bool p_separator);
void set_item_as_checkable(int p_idx, bool p_checkable);
+ void set_item_as_radio_checkable(int p_idx, bool p_radio_checkable);
void set_item_tooltip(int p_idx, const String &p_tooltip);
void set_item_shortcut(int p_idx, const Ref<ShortCut> &p_shortcut, bool p_global = false);
void set_item_h_offset(int p_idx, int p_offset);
@@ -152,6 +164,7 @@ public:
String get_item_submenu(int p_idx) const;
bool is_item_separator(int p_idx) const;
bool is_item_checkable(int p_idx) const;
+ bool is_item_radio_checkable(int p_idx) const;
String get_item_tooltip(int p_idx) const;
Ref<ShortCut> get_item_shortcut(int p_idx) const;
int get_item_state(int p_idx) const;
@@ -176,7 +189,6 @@ public:
void add_autohide_area(const Rect2 &p_area);
void clear_autohide_areas();
- void set_invalidate_click_until_motion();
void set_hide_on_item_selection(bool p_enabled);
bool is_hide_on_item_selection() const;
@@ -186,6 +198,8 @@ public:
void set_hide_on_multistate_item_selection(bool p_enabled);
bool is_hide_on_multistate_item_selection() const;
+ virtual void popup(const Rect2 &p_bounds = Rect2());
+
PopupMenu();
~PopupMenu();
};
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 6953d03384..37e519e375 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,18 +27,22 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "progress_bar.h"
Size2 ProgressBar::get_minimum_size() const {
Ref<StyleBox> bg = get_stylebox("bg");
+ Ref<StyleBox> fg = get_stylebox("fg");
Ref<Font> font = get_font("font");
- Size2 ms = bg->get_minimum_size() + bg->get_center_size();
+ Size2 minimum_size = bg->get_minimum_size();
+ minimum_size.height = MAX(minimum_size.height, fg->get_minimum_size().height);
+ minimum_size.width = MAX(minimum_size.width, fg->get_minimum_size().width);
if (percent_visible) {
- ms.height = MAX(ms.height, bg->get_minimum_size().height + font->get_height());
+ minimum_size.height = MAX(minimum_size.height, bg->get_minimum_size().height + font->get_height());
}
- return ms;
+ return minimum_size;
}
void ProgressBar::_notification(int p_what) {
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index c5a9252123..d091c983b1 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PROGRESS_BAR_H
#define PROGRESS_BAR_H
diff --git a/scene/gui/range.cpp b/scene/gui/range.cpp
index f8fb786fa7..4062e48640 100644
--- a/scene/gui/range.cpp
+++ b/scene/gui/range.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "range.h"
void Range::_value_changed_notify() {
@@ -70,10 +71,10 @@ void Range::set_value(double p_val) {
p_val = Math::round(p_val);
}
- if (p_val > shared->max - shared->page)
+ if (!shared->allow_greater && p_val > shared->max - shared->page)
p_val = shared->max - shared->page;
- if (p_val < shared->min)
+ if (!shared->allow_lesser && p_val < shared->min)
p_val = shared->min;
if (shared->val == p_val)
@@ -135,9 +136,9 @@ void Range::set_as_ratio(double p_value) {
double v;
- if (shared->exp_ratio && get_min() > 0) {
+ if (shared->exp_ratio && get_min() >= 0) {
- double exp_min = Math::log(get_min()) / Math::log((double)2);
+ double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2);
double exp_max = Math::log(get_max()) / Math::log((double)2);
v = Math::pow(2, exp_min + (exp_max - exp_min) * p_value);
} else {
@@ -150,21 +151,24 @@ void Range::set_as_ratio(double p_value) {
v = percent + get_min();
}
}
+ v = CLAMP(v, get_min(), get_max());
set_value(v);
}
double Range::get_as_ratio() const {
- if (shared->exp_ratio && get_min() > 0) {
+ if (shared->exp_ratio && get_min() >= 0) {
- double exp_min = Math::log(get_min()) / Math::log((double)2);
+ double exp_min = get_min() == 0 ? 0.0 : Math::log(get_min()) / Math::log((double)2);
double exp_max = Math::log(get_max()) / Math::log((double)2);
- double v = Math::log(get_value()) / Math::log((double)2);
+ float value = CLAMP(get_value(), shared->min, shared->max);
+ double v = Math::log(value) / Math::log((double)2);
return (v - exp_min) / (exp_max - exp_min);
} else {
- return (get_value() - get_min()) / (get_max() - get_min());
+ float value = CLAMP(get_value(), shared->min, shared->max);
+ return (value - get_min()) / (get_max() - get_min());
}
}
@@ -192,6 +196,8 @@ void Range::unshare() {
nshared->val = shared->val;
nshared->step = shared->step;
nshared->page = shared->page;
+ nshared->allow_greater = shared->allow_greater;
+ nshared->allow_lesser = shared->allow_lesser;
_unref_shared();
_ref_shared(nshared);
}
@@ -235,6 +241,10 @@ void Range::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_using_rounded_values"), &Range::is_using_rounded_values);
ClassDB::bind_method(D_METHOD("set_exp_ratio", "enabled"), &Range::set_exp_ratio);
ClassDB::bind_method(D_METHOD("is_ratio_exp"), &Range::is_ratio_exp);
+ ClassDB::bind_method(D_METHOD("set_allow_greater", "allow"), &Range::set_allow_greater);
+ ClassDB::bind_method(D_METHOD("is_greater_allowed"), &Range::is_greater_allowed);
+ ClassDB::bind_method(D_METHOD("set_allow_lesser", "allow"), &Range::set_allow_lesser);
+ ClassDB::bind_method(D_METHOD("is_lesser_allowed"), &Range::is_lesser_allowed);
ClassDB::bind_method(D_METHOD("share", "with"), &Range::_share);
ClassDB::bind_method(D_METHOD("unshare"), &Range::unshare);
@@ -247,8 +257,11 @@ void Range::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "step"), "set_step", "get_step");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "page"), "set_page", "get_page");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "value"), "set_value", "get_value");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "ratio", PROPERTY_HINT_RANGE, "0,1,0.01", 0), "set_as_ratio", "get_as_ratio");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "exp_edit"), "set_exp_ratio", "is_ratio_exp");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "rounded"), "set_use_rounded_values", "is_using_rounded_values");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_greater"), "set_allow_greater", "is_greater_allowed");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "allow_lesser"), "set_allow_lesser", "is_lesser_allowed");
}
void Range::set_use_rounded_values(bool p_enable) {
@@ -271,6 +284,22 @@ bool Range::is_ratio_exp() const {
return shared->exp_ratio;
}
+void Range::set_allow_greater(bool p_allow) {
+ shared->allow_greater = p_allow;
+}
+
+bool Range::is_greater_allowed() const {
+ return shared->allow_greater;
+}
+
+void Range::set_allow_lesser(bool p_allow) {
+ shared->allow_lesser = p_allow;
+}
+
+bool Range::is_lesser_allowed() const {
+ return shared->allow_lesser;
+}
+
Range::Range() {
shared = memnew(Shared);
shared->min = 0;
@@ -280,6 +309,8 @@ Range::Range() {
shared->page = 0;
shared->owners.insert(this);
shared->exp_ratio = false;
+ shared->allow_greater = false;
+ shared->allow_lesser = false;
_rounded_values = false;
}
diff --git a/scene/gui/range.h b/scene/gui/range.h
index daa8af824a..125f559248 100644
--- a/scene/gui/range.h
+++ b/scene/gui/range.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RANGE_H
#define RANGE_H
@@ -42,6 +43,8 @@ class Range : public Control {
double val, min, max;
double step, page;
bool exp_ratio;
+ bool allow_greater;
+ bool allow_lesser;
Set<Range *> owners;
void emit_value_changed();
void emit_changed(const char *p_what = "");
@@ -85,6 +88,12 @@ public:
void set_exp_ratio(bool p_enable);
bool is_ratio_exp() const;
+ void set_allow_greater(bool p_allow);
+ bool is_greater_allowed() const;
+
+ void set_allow_lesser(bool p_allow);
+ bool is_lesser_allowed() const;
+
void share(Range *p_range);
void unshare();
diff --git a/scene/gui/reference_rect.cpp b/scene/gui/reference_rect.cpp
index e2f4abe04a..5e25f43daf 100644
--- a/scene/gui/reference_rect.cpp
+++ b/scene/gui/reference_rect.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "reference_rect.h"
#include "engine.h"
diff --git a/scene/gui/reference_rect.h b/scene/gui/reference_rect.h
index 9b826a1145..473e348c85 100644
--- a/scene/gui/reference_rect.h
+++ b/scene/gui/reference_rect.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef REFERENCE_RECT_H
#define REFERENCE_RECT_H
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 05c6e9f77e..f34559fc8d 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,10 +27,16 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "rich_text_label.h"
#include "os/keyboard.h"
#include "os/os.h"
#include "scene/scene_string_names.h"
+
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#endif
+
RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
if (p_free) {
@@ -80,11 +86,59 @@ RichTextLabel::Item *RichTextLabel::_get_next_item(Item *p_item, bool p_free) {
return NULL;
}
+RichTextLabel::Item *RichTextLabel::_get_prev_item(Item *p_item, bool p_free) {
+ if (p_free) {
+
+ if (p_item->subitems.size()) {
+
+ return p_item->subitems.back()->get();
+ } else if (!p_item->parent) {
+ return NULL;
+ } else if (p_item->E->prev()) {
+
+ return p_item->E->prev()->get();
+ } else {
+ //go back until something with a prev is found
+ while (p_item->parent && !p_item->E->prev()) {
+ p_item = p_item->parent;
+ }
+
+ if (p_item->parent)
+ return p_item->E->prev()->get();
+ else
+ return NULL;
+ }
+
+ } else {
+ if (p_item->subitems.size() && p_item->type != ITEM_TABLE) {
+
+ return p_item->subitems.back()->get();
+ } else if (p_item->type == ITEM_FRAME) {
+ return NULL;
+ } else if (p_item->E->prev()) {
+
+ return p_item->E->prev()->get();
+ } else {
+ //go back until something with a prev is found
+ while (p_item->type != ITEM_FRAME && !p_item->E->prev()) {
+ p_item = p_item->parent;
+ }
+
+ if (p_item->type != ITEM_FRAME)
+ return p_item->E->prev()->get();
+ else
+ return NULL;
+ }
+ }
+
+ return NULL;
+}
+
Rect2 RichTextLabel::_get_text_rect() {
Ref<StyleBox> style = get_stylebox("normal");
return Rect2(style->get_offset(), get_size() - style->get_minimum_size());
}
-int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) {
+int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos, Item **r_click_item, int *r_click_char, bool *r_outside, int p_char_count) {
RID ci;
if (r_outside)
@@ -115,8 +169,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (p_mode == PROCESS_CACHE) {
l.offset_caches.clear();
l.height_caches.clear();
+ l.ascent_caches.clear();
+ l.descent_caches.clear();
l.char_count = 0;
l.minimum_width = 0;
+ l.maximum_width = 0;
}
int wofs = margin;
@@ -134,6 +191,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
//line height should be the font height for the first time, this ensures that an empty line will never have zero height and successive newlines are displayed
int line_height = cfont->get_height();
+ int line_ascent = cfont->get_ascent();
+ int line_descent = cfont->get_descent();
int nonblank_line_count = 0; //number of nonblank lines as counted during PROCESS_DRAW
@@ -163,16 +222,22 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
case ALIGN_FILL: l.offset_caches.push_back((p_width - margin) - used /*+spaces_size*/); break; \
} \
l.height_caches.push_back(line_height); \
+ l.ascent_caches.push_back(line_ascent); \
+ l.descent_caches.push_back(line_descent); \
l.space_caches.push_back(spaces); \
} \
y += line_height + get_constant(SceneStringNames::get_singleton()->line_separation); \
line_height = 0; \
+ line_ascent = 0; \
+ line_descent = 0; \
spaces = 0; \
spaces_size = 0; \
wofs = begin; \
align_ofs = 0; \
if (p_mode != PROCESS_CACHE) { \
lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \
+ line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1; \
+ line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1; \
} \
if (p_mode == PROCESS_POINTER && r_click_item && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh && p_click_pos.x < p_ofs.x + wofs) { \
if (r_outside) *r_outside = true; \
@@ -184,7 +249,8 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
#define ENSURE_WIDTH(m_width) \
if (p_mode == PROCESS_CACHE) { \
- l.minimum_width = MAX(l.minimum_width, wofs + m_width); \
+ l.maximum_width = MAX(l.maximum_width, MIN(p_width, wofs + m_width)); \
+ l.minimum_width = MAX(l.minimum_width, m_width); \
} \
if (wofs + m_width > p_width) { \
if (p_mode == PROCESS_CACHE) { \
@@ -231,6 +297,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int rchar = 0;
int lh = 0;
bool line_is_blank = true;
+ int fh = 0;
while (it) {
@@ -246,13 +313,16 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
const CharType *c = text->text.c_str();
const CharType *cf = c;
- int fh = font->get_height();
int ascent = font->get_ascent();
+ int descent = font->get_descent();
+
Color color;
+ Color font_color_shadow;
bool underline = false;
if (p_mode == PROCESS_DRAW) {
color = _find_color(text, p_base_color);
+ font_color_shadow = _find_color(text, p_font_color_shadow);
underline = _find_underline(text);
if (_find_meta(text, &meta)) {
@@ -264,7 +334,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
}
rchar = 0;
-
+ FontDrawer drawer(font, Color(1, 1, 1));
while (*c) {
int end = 0;
@@ -274,8 +344,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
lh = 0;
if (p_mode != PROCESS_CACHE) {
lh = line < l.height_caches.size() ? l.height_caches[line] : 1;
+ line_ascent = line < l.ascent_caches.size() ? l.ascent_caches[line] : 1;
+ line_descent = line < l.descent_caches.size() ? l.descent_caches[line] : 1;
}
-
while (c[end] != 0 && !(end && c[end - 1] == ' ' && c[end] != ' ')) {
int cw = font->get_char_size(c[end], c[end + 1]).width;
@@ -292,9 +363,13 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
end++;
}
-
+ CHECK_HEIGHT(fh);
ENSURE_WIDTH(w);
+ line_ascent = MAX(line_ascent, ascent);
+ line_descent = MAX(line_descent, descent);
+ fh = line_ascent + line_descent;
+
if (end && c[end - 1] == ' ') {
if (p_mode == PROCESS_CACHE) {
spaces_size += font->get_char_size(' ').width;
@@ -342,23 +417,37 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int cw = 0;
- bool visible = visible_characters < 0 || p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - (fh - 0 * ascent), fh); //getting rid of ascent seems to work??
+ bool visible = visible_characters < 0 || p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - line_descent - line_ascent, line_ascent + line_descent);
if (visible)
line_is_blank = false;
if (c[i] == '\t')
visible = false;
- if (selected) {
+ if (visible) {
+ if (selected) {
+ cw = font->get_char_size(c[i], c[i + 1]).x;
+ draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg);
+ }
- cw = font->get_char_size(c[i], c[i + 1]).x;
- draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg);
- if (visible)
- font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - (fh - ascent)), c[i], c[i + 1], override_selected_font_color ? selection_fg : color);
+ if (p_font_color_shadow.a > 0) {
+ float x_ofs_shadow = align_ofs + pofs;
+ float y_ofs_shadow = y + lh - line_descent;
+ float move = font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs, c[i], c[i + 1], p_font_color_shadow);
+
+ if (p_shadow_as_outline) {
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y), c[i], c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y), c[i], c[i + 1], p_font_color_shadow);
+ font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y), c[i], c[i + 1], p_font_color_shadow);
+ }
+ x_ofs_shadow += move;
+ }
- } else {
- if (visible)
- cw = font->draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - (fh - ascent)), c[i], c[i + 1], color);
+ if (selected) {
+ drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), c[i], c[i + 1], override_selected_font_color ? selection_fg : color);
+ } else {
+ cw = drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), c[i], c[i + 1], color);
+ }
}
p_char_count++;
@@ -366,15 +455,20 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
cw = tab_size * font->get_char_size(' ').width;
}
- if (underline) {
- Color uc = color;
- uc.a *= 0.5;
- int uy = y + lh - fh + ascent + 2;
- VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + pofs, uy), p_ofs + Point2(align_ofs + pofs + cw, uy), uc);
- }
ofs += cw;
}
}
+
+ if (underline) {
+ Color uc = color;
+ uc.a *= 0.5;
+ int uy = y + lh - line_descent + 2;
+ float underline_width = 1.0;
+#ifdef TOOLS_ENABLED
+ underline_width *= EDSCALE;
+#endif
+ VS::get_singleton()->canvas_item_add_line(ci, p_ofs + Point2(align_ofs + wofs, uy), p_ofs + Point2(align_ofs + wofs + w, uy), uc, underline_width);
+ }
}
ADVANCE(fw);
@@ -432,6 +526,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
int vseparation = get_constant("table_vseparation");
Color ccolor = _find_color(table, p_base_color);
Vector2 draw_ofs = Point2(wofs, y);
+ Color font_color_shadow = get_color("font_color_shadow");
+ bool use_outline = get_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
if (p_mode == PROCESS_CACHE) {
@@ -439,9 +536,12 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
//set minimums to zero
for (int i = 0; i < table->columns.size(); i++) {
table->columns[i].min_width = 0;
+ table->columns[i].max_width = 0;
table->columns[i].width = 0;
}
//compute minimum width for each cell
+ const int available_width = p_width - hseparation * (table->columns.size() - 1) - wofs;
+
for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
ERR_CONTINUE(E->get()->type != ITEM_FRAME); //children should all be frames
ItemFrame *frame = static_cast<ItemFrame *>(E->get());
@@ -452,8 +552,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
for (int i = 0; i < frame->lines.size(); i++) {
- _process_line(frame, Point2(), ly, p_width, i, PROCESS_CACHE, cfont, Color());
+ _process_line(frame, Point2(), ly, available_width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs);
table->columns[column].min_width = MAX(table->columns[column].min_width, frame->lines[i].minimum_width);
+ table->columns[column].max_width = MAX(table->columns[column].max_width, frame->lines[i].maximum_width);
}
idx++;
}
@@ -461,24 +562,58 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
//compute available width and total ratio (for expanders)
int total_ratio = 0;
- int available_width = p_width - hseparation * (table->columns.size() - 1);
+ int remaining_width = available_width;
table->total_width = hseparation;
for (int i = 0; i < table->columns.size(); i++) {
- available_width -= table->columns[i].min_width;
+ remaining_width -= table->columns[i].min_width;
+ if (table->columns[i].max_width > table->columns[i].min_width)
+ table->columns[i].expand = true;
if (table->columns[i].expand)
total_ratio += table->columns[i].expand_ratio;
}
//assign actual widths
-
for (int i = 0; i < table->columns.size(); i++) {
table->columns[i].width = table->columns[i].min_width;
if (table->columns[i].expand)
- table->columns[i].width += table->columns[i].expand_ratio * available_width / total_ratio;
+ table->columns[i].width += table->columns[i].expand_ratio * remaining_width / total_ratio;
table->total_width += table->columns[i].width + hseparation;
}
+ //resize to max_width if needed and distribute the remaining space
+ bool table_need_fit = true;
+ while (table_need_fit) {
+ table_need_fit = false;
+ //fit slim
+ for (int i = 0; i < table->columns.size(); i++) {
+ if (!table->columns[i].expand)
+ continue;
+ int dif = table->columns[i].width - table->columns[i].max_width;
+ if (dif > 0) {
+ table_need_fit = true;
+ table->columns[i].width = table->columns[i].max_width;
+ table->total_width -= dif;
+ total_ratio -= table->columns[i].expand_ratio;
+ }
+ }
+ //grow
+ remaining_width = available_width - table->total_width;
+ if (remaining_width > 0 && total_ratio > 0) {
+ for (int i = 0; i < table->columns.size(); i++) {
+ if (table->columns[i].expand) {
+ int dif = table->columns[i].max_width - table->columns[i].width;
+ if (dif > 0) {
+ int slice = table->columns[i].expand_ratio * remaining_width / total_ratio;
+ int incr = MIN(dif, slice);
+ table->columns[i].width += incr;
+ table->total_width += incr;
+ }
+ }
+ }
+ }
+ }
+
//compute caches properly again with the right width
idx = 0;
for (List<Item *>::Element *E = table->subitems.front(); E; E = E->next()) {
@@ -490,7 +625,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
for (int i = 0; i < frame->lines.size(); i++) {
int ly = 0;
- _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color());
+ _process_line(frame, Point2(), ly, table->columns[column].width, i, PROCESS_CACHE, cfont, Color(), font_color_shadow, use_outline, shadow_ofs);
frame->lines[i].height_cache = ly; //actual height
frame->lines[i].height_accum_cache = ly; //actual height
}
@@ -523,9 +658,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (visible) {
if (p_mode == PROCESS_DRAW) {
- nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor);
+ nonblank_line_count += _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_DRAW, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs);
} else if (p_mode == PROCESS_POINTER) {
- _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, p_click_pos, r_click_item, r_click_char, r_outside);
+ _process_line(frame, p_ofs + offset + draw_ofs + Vector2(0, yofs), ly, table->columns[column].width, i, PROCESS_POINTER, cfont, ccolor, font_color_shadow, use_outline, shadow_ofs, p_click_pos, r_click_item, r_click_char, r_outside);
if (r_click_item && *r_click_item) {
RETURN; // exit early
}
@@ -606,9 +741,7 @@ void RichTextLabel::_scroll_changed(double) {
void RichTextLabel::_update_scroll() {
- int total_height = 0;
- if (main->lines.size())
- total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_stylebox("normal")->get_minimum_size().height;
+ int total_height = get_content_height();
bool exceeds = total_height > get_size().height && scroll_active;
@@ -697,12 +830,18 @@ void RichTextLabel::_notification(int p_what) {
int y = (main->lines[from_line].height_accum_cache - main->lines[from_line].height_cache) - ofs;
Ref<Font> base_font = get_font("normal_font");
Color base_color = get_color("default_color");
+ Color font_color_shadow = get_color("font_color_shadow");
+ bool use_outline = get_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
+
+ float x_ofs = 0;
visible_line_count = 0;
while (y < size.height && from_line < main->lines.size()) {
- visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, Point2i(), NULL, NULL, NULL, total_chars);
+ visible_line_count += _process_line(main, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_DRAW, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, Point2i(), NULL, NULL, NULL, total_chars);
total_chars += main->lines[from_line].char_count;
+
from_line++;
}
}
@@ -717,6 +856,9 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
Size2 size = get_size();
Rect2 text_rect = _get_text_rect();
int ofs = vscroll->get_value();
+ Color font_color_shadow = get_color("font_color_shadow");
+ bool use_outline = get_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
//todo, change to binary search
int from_line = 0;
@@ -737,7 +879,7 @@ void RichTextLabel::_find_click(ItemFrame *p_frame, const Point2i &p_click, Item
while (y < text_rect.get_size().height && from_line < p_frame->lines.size()) {
- _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, p_click, r_click_item, r_click_char, r_outside);
+ _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, from_line, PROCESS_POINTER, base_font, base_color, font_color_shadow, use_outline, shadow_ofs, p_click, r_click_item, r_click_char, r_outside);
if (r_click_item && *r_click_item)
return;
from_line++;
@@ -797,16 +939,44 @@ void RichTextLabel::_gui_input(Ref<InputEvent> p_event) {
// Erase previous selection.
if (selection.active) {
selection.from = NULL;
- selection.from_char = NULL;
+ selection.from_char = '\0';
selection.to = NULL;
- selection.to_char = NULL;
+ selection.to_char = '\0';
selection.active = false;
update();
}
}
}
+ } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) {
+
+ //doubleclick: select word
+ int line = 0;
+ Item *item = NULL;
+ bool outside;
+
+ _find_click(main, b->get_position(), &item, &line, &outside);
+
+ while (item && item->type != ITEM_TEXT) {
+
+ item = _get_next_item(item, true);
+ }
+ if (item && item->type == ITEM_TEXT) {
+
+ String itext = static_cast<ItemText *>(item)->text;
+
+ int beg, end;
+ if (select_word(itext, line, beg, end)) {
+
+ selection.from = item;
+ selection.to = item;
+ selection.from_char = beg;
+ selection.to_char = end - 1;
+ selection.active = true;
+ update();
+ }
+ }
} else if (!b->is_pressed()) {
selection.click = NULL;
@@ -1084,13 +1254,16 @@ void RichTextLabel::_validate_line_caches(ItemFrame *p_frame) {
//validate invalid lines
Size2 size = get_size();
Rect2 text_rect = _get_text_rect();
+ Color font_color_shadow = get_color("font_color_shadow");
+ bool use_outline = get_constant("shadow_as_outline");
+ Point2 shadow_ofs(get_constant("shadow_offset_x"), get_constant("shadow_offset_y"));
Ref<Font> base_font = get_font("normal_font");
for (int i = p_frame->first_invalid_line; i < p_frame->lines.size(); i++) {
int y = 0;
- _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color());
+ _process_line(p_frame, text_rect.get_position(), y, text_rect.get_size().width - scroll_w, i, PROCESS_CACHE, base_font, Color(), font_color_shadow, use_outline, shadow_ofs);
p_frame->lines[i].height_cache = y;
p_frame->lines[i].height_accum_cache = y;
@@ -1573,7 +1746,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
tag_stack.push_front(tag);
} else if (tag.begins_with("cell=")) {
- int ratio = tag.substr(6, tag.length()).to_int();
+ int ratio = tag.substr(5, tag.length()).to_int();
if (ratio < 1)
ratio = 1;
//use monospace font
@@ -1764,7 +1937,7 @@ void RichTextLabel::set_selection_enabled(bool p_enabled) {
}
}
-bool RichTextLabel::search(const String &p_string, bool p_from_selection) {
+bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p_search_previous) {
ERR_FAIL_COND_V(!selection.enabled, false);
Item *it = main;
@@ -1813,7 +1986,10 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection) {
}
}
- it = _get_next_item(it, true);
+ if (p_search_previous)
+ it = _get_prev_item(it, true);
+ else
+ it = _get_next_item(it, true);
charidx = 0;
}
@@ -1932,6 +2108,13 @@ float RichTextLabel::get_percent_visible() const {
return percent_visible;
}
+int RichTextLabel::get_content_height() {
+ int total_height = 0;
+ if (main->lines.size())
+ total_height = main->lines[main->lines.size() - 1].height_accum_cache + get_stylebox("normal")->get_minimum_size().height;
+ return total_height;
+}
+
void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &RichTextLabel::_gui_input);
@@ -1998,12 +2181,23 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &RichTextLabel::get_line_count);
ClassDB::bind_method(D_METHOD("get_visible_line_count"), &RichTextLabel::get_visible_line_count);
+ ClassDB::bind_method(D_METHOD("get_content_height"), &RichTextLabel::get_content_height);
+
ADD_GROUP("BBCode", "bbcode_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bbcode_text", PROPERTY_HINT_MULTILINE_TEXT), "set_bbcode", "get_bbcode");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_active"), "set_scroll_active", "is_scroll_active");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_following"), "set_scroll_follow", "is_scroll_following");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_SIGNAL(MethodInfo("meta_clicked", PropertyInfo(Variant::NIL, "meta", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index b9a719dd10..af368af46a 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RICH_TEXT_LABEL_H
#define RICH_TEXT_LABEL_H
@@ -79,11 +80,14 @@ private:
Item *from;
Vector<int> offset_caches;
Vector<int> height_caches;
+ Vector<int> ascent_caches;
+ Vector<int> descent_caches;
Vector<int> space_caches;
int height_cache;
int height_accum_cache;
int char_count;
int minimum_width;
+ int maximum_width;
Line() {
from = NULL;
@@ -186,7 +190,6 @@ private:
struct ItemNewline : public Item {
- int line; // FIXME: Overriding base's line ?
ItemNewline() { type = ITEM_NEWLINE; }
};
@@ -196,6 +199,7 @@ private:
bool expand;
int expand_ratio;
int min_width;
+ int max_width;
int width;
};
@@ -265,7 +269,7 @@ private:
int visible_characters;
float percent_visible;
- int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Point2i &p_click_pos = Point2i(), Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL, int p_char_count = 0);
+ int _process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &y, int p_width, int p_line, ProcessMode p_mode, const Ref<Font> &p_base_font, const Color &p_base_color, const Color &p_font_color_shadow, bool p_shadow_as_outline, const Point2 &shadow_ofs, const Point2i &p_click_pos = Point2i(), Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL, int p_char_count = 0);
void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL);
Ref<Font> _find_font(Item *p_item);
@@ -280,6 +284,7 @@ private:
void _gui_input(Ref<InputEvent> p_event);
Item *_get_next_item(Item *p_item, bool p_free = false);
+ Item *_get_prev_item(Item *p_item, bool p_free = false);
Rect2 _get_text_rect();
@@ -329,12 +334,14 @@ public:
void set_tab_size(int p_spaces);
int get_tab_size() const;
- bool search(const String &p_string, bool p_from_selection = false);
+ bool search(const String &p_string, bool p_from_selection = false, bool p_search_previous = false);
void scroll_to_line(int p_line);
int get_line_count() const;
int get_visible_line_count() const;
+ int get_content_height();
+
VScrollBar *get_v_scroll() { return vscroll; }
virtual CursorShape get_cursor_shape(const Point2 &p_pos) const;
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index c5ffec2d5e..6ec67aca6b 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "scroll_bar.h"
#include "os/keyboard.h"
@@ -113,7 +114,7 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
if (smooth_scroll_enabled) {
scrolling = true;
- set_physics_process(true);
+ set_physics_process_internal(true);
} else {
set_value(target_scroll);
}
@@ -137,7 +138,7 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
if (smooth_scroll_enabled) {
scrolling = true;
- set_physics_process(true);
+ set_physics_process_internal(true);
} else {
set_value(target_scroll);
}
@@ -198,54 +199,40 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
}
}
- Ref<InputEventKey> k = p_event;
-
- if (k.is_valid()) {
-
- if (!k->is_pressed())
- return;
+ if (p_event->is_pressed()) {
- switch (k->get_scancode()) {
-
- case KEY_LEFT: {
-
- if (orientation != HORIZONTAL)
- return;
- set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
+ if (p_event->is_action("ui_left")) {
- } break;
- case KEY_RIGHT: {
+ if (orientation != HORIZONTAL)
+ return;
+ set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- if (orientation != HORIZONTAL)
- return;
- set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
+ } else if (p_event->is_action("ui_right")) {
- } break;
- case KEY_UP: {
+ if (orientation != HORIZONTAL)
+ return;
+ set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- if (orientation != VERTICAL)
- return;
+ } else if (p_event->is_action("ui_up")) {
- set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
+ if (orientation != VERTICAL)
+ return;
- } break;
- case KEY_DOWN: {
+ set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
- if (orientation != VERTICAL)
- return;
- set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
+ } else if (p_event->is_action("ui_down")) {
- } break;
- case KEY_HOME: {
+ if (orientation != VERTICAL)
+ return;
+ set_value(get_value() + (custom_step >= 0 ? custom_step : get_step()));
- set_value(get_min());
+ } else if (p_event->is_action("ui_home")) {
- } break;
- case KEY_END: {
+ set_value(get_min());
- set_value(get_max());
+ } else if (p_event->is_action("ui_end")) {
- } break;
+ set_value(get_max());
}
}
}
@@ -322,20 +309,20 @@ void ScrollBar::_notification(int p_what) {
if (drag_slave) {
drag_slave->connect("gui_input", this, "_drag_slave_input");
- drag_slave->connect("tree_exited", this, "_drag_slave_exit", varray(), CONNECT_ONESHOT);
+ drag_slave->connect("tree_exiting", this, "_drag_slave_exit", varray(), CONNECT_ONESHOT);
}
}
if (p_what == NOTIFICATION_EXIT_TREE) {
if (drag_slave) {
drag_slave->disconnect("gui_input", this, "_drag_slave_input");
- drag_slave->disconnect("tree_exited", this, "_drag_slave_exit");
+ drag_slave->disconnect("tree_exiting", this, "_drag_slave_exit");
}
drag_slave = NULL;
}
- if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
+ if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
if (scrolling) {
if (get_value() != target_scroll) {
@@ -350,7 +337,7 @@ void ScrollBar::_notification(int p_what) {
}
} else {
scrolling = false;
- set_physics_process(false);
+ set_physics_process_internal(false);
}
} else if (drag_slave_touching) {
@@ -410,7 +397,7 @@ void ScrollBar::_notification(int p_what) {
}
if (turnoff) {
- set_physics_process(false);
+ set_physics_process_internal(false);
drag_slave_touching = false;
drag_slave_touching_deaccel = false;
}
@@ -579,7 +566,7 @@ void ScrollBar::_drag_slave_input(const Ref<InputEvent> &p_input) {
if (mb->is_pressed()) {
if (drag_slave_touching) {
- set_physics_process(false);
+ set_physics_process_internal(false);
drag_slave_touching_deaccel = false;
drag_slave_touching = false;
drag_slave_speed = Vector2();
@@ -599,7 +586,7 @@ void ScrollBar::_drag_slave_input(const Ref<InputEvent> &p_input) {
drag_slave_touching_deaccel = false;
time_since_motion = 0;
if (drag_slave_touching) {
- set_physics_process(true);
+ set_physics_process_internal(true);
time_since_motion = 0;
}
}
@@ -611,7 +598,7 @@ void ScrollBar::_drag_slave_input(const Ref<InputEvent> &p_input) {
if (drag_slave_speed == Vector2()) {
drag_slave_touching_deaccel = false;
drag_slave_touching = false;
- set_physics_process(false);
+ set_physics_process_internal(false);
} else {
drag_slave_touching_deaccel = true;
@@ -654,7 +641,7 @@ void ScrollBar::set_drag_slave(const NodePath &p_path) {
if (drag_slave) {
drag_slave->disconnect("gui_input", this, "_drag_slave_input");
- drag_slave->disconnect("tree_exited", this, "_drag_slave_exit");
+ drag_slave->disconnect("tree_exiting", this, "_drag_slave_exit");
}
}
@@ -670,7 +657,7 @@ void ScrollBar::set_drag_slave(const NodePath &p_path) {
if (drag_slave) {
drag_slave->connect("gui_input", this, "_drag_slave_input");
- drag_slave->connect("tree_exited", this, "_drag_slave_exit", varray(), CONNECT_ONESHOT);
+ drag_slave->connect("tree_exiting", this, "_drag_slave_exit", varray(), CONNECT_ONESHOT);
}
}
}
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index 753bd35de7..15e037f8bb 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCROLL_BAR_H
#define SCROLL_BAR_H
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index ffe0db691f..2dd5c64378 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "scroll_container.h"
#include "os/os.h"
bool ScrollContainer::clips_input() const {
@@ -36,6 +37,7 @@ bool ScrollContainer::clips_input() const {
Size2 ScrollContainer::get_minimum_size() const {
+ Ref<StyleBox> sb = get_stylebox("bg");
Size2 min_size;
for (int i = 0; i < get_child_count(); i++) {
@@ -63,17 +65,24 @@ Size2 ScrollContainer::get_minimum_size() const {
if (v_scroll->is_visible_in_tree()) {
min_size.x += v_scroll->get_minimum_size().x;
}
+ min_size += sb->get_minimum_size();
return min_size;
-};
+}
void ScrollContainer::_cancel_drag() {
- set_physics_process(false);
+ set_physics_process_internal(false);
drag_touching_deaccel = false;
drag_touching = false;
drag_speed = Vector2();
drag_accum = Vector2();
last_drag_accum = Vector2();
drag_from = Vector2();
+
+ if (beyond_deadzone) {
+ emit_signal("scroll_ended");
+ propagate_notification(NOTIFICATION_SCROLL_END);
+ beyond_deadzone = false;
+ }
}
void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
@@ -121,13 +130,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->is_pressed()) {
if (drag_touching) {
- set_physics_process(false);
- drag_touching_deaccel = false;
- drag_touching = false;
- drag_speed = Vector2();
- drag_accum = Vector2();
- last_drag_accum = Vector2();
- drag_from = Vector2();
+ _cancel_drag();
}
if (true) {
@@ -137,9 +140,10 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value());
drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
drag_touching_deaccel = false;
+ beyond_deadzone = false;
time_since_motion = 0;
if (drag_touching) {
- set_physics_process(true);
+ set_physics_process_internal(true);
time_since_motion = 0;
}
}
@@ -148,9 +152,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (drag_touching) {
if (drag_speed == Vector2()) {
- drag_touching_deaccel = false;
- drag_touching = false;
- set_physics_process(false);
+ _cancel_drag();
} else {
drag_touching_deaccel = true;
@@ -167,17 +169,27 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
drag_accum -= motion;
- Vector2 diff = drag_from + drag_accum;
-
- if (scroll_h)
- h_scroll->set_value(diff.x);
- else
- drag_accum.x = 0;
- if (scroll_v)
- v_scroll->set_value(diff.y);
- else
- drag_accum.y = 0;
- time_since_motion = 0;
+
+ if (beyond_deadzone || scroll_h && Math::abs(drag_accum.x) > deadzone || scroll_v && Math::abs(drag_accum.y) > deadzone) {
+ if (!beyond_deadzone) {
+ propagate_notification(NOTIFICATION_SCROLL_BEGIN);
+ emit_signal("scroll_started");
+
+ beyond_deadzone = true;
+ // resetting drag_accum here ensures smooth scrolling after reaching deadzone
+ drag_accum = -motion;
+ }
+ Vector2 diff = drag_from + drag_accum;
+ if (scroll_h)
+ h_scroll->set_value(diff.x);
+ else
+ drag_accum.x = 0;
+ if (scroll_v)
+ v_scroll->set_value(diff.y);
+ else
+ drag_accum.y = 0;
+ time_since_motion = 0;
+ }
}
}
@@ -223,6 +235,12 @@ void ScrollContainer::_notification(int p_what) {
child_max_size = Size2(0, 0);
Size2 size = get_size();
+ Point2 ofs;
+
+ Ref<StyleBox> sb = get_stylebox("bg");
+ size -= sb->get_minimum_size();
+ ofs += sb->get_offset();
+
if (h_scroll->is_visible_in_tree())
size.y -= h_scroll->get_minimum_size().y;
@@ -258,6 +276,7 @@ void ScrollContainer::_notification(int p_what) {
else
r.size.height = minsize.height;
}
+ r.position += ofs;
fit_child_in_rect(c, r);
}
update();
@@ -265,10 +284,13 @@ void ScrollContainer::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
+ Ref<StyleBox> sb = get_stylebox("bg");
+ draw_style_box(sb, Rect2(Vector2(), get_size()));
+
update_scrollbars();
}
- if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
+ if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
if (drag_touching) {
@@ -322,9 +344,7 @@ void ScrollContainer::_notification(int p_what) {
drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y);
if (turnoff_h && turnoff_v) {
- set_physics_process(false);
- drag_touching = false;
- drag_touching_deaccel = false;
+ _cancel_drag();
}
} else {
@@ -345,6 +365,8 @@ void ScrollContainer::_notification(int p_what) {
void ScrollContainer::update_scrollbars() {
Size2 size = get_size();
+ Ref<StyleBox> sb = get_stylebox("bg");
+ size -= sb->get_minimum_size();
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
@@ -429,6 +451,14 @@ void ScrollContainer::set_h_scroll(int p_pos) {
_cancel_drag();
}
+int ScrollContainer::get_deadzone() const {
+ return deadzone;
+}
+
+void ScrollContainer::set_deadzone(int p_deadzone) {
+ deadzone = p_deadzone;
+}
+
String ScrollContainer::get_configuration_warning() const {
int found = 0;
@@ -461,14 +491,24 @@ void ScrollContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_enable_v_scroll", "enable"), &ScrollContainer::set_enable_v_scroll);
ClassDB::bind_method(D_METHOD("is_v_scroll_enabled"), &ScrollContainer::is_v_scroll_enabled);
ClassDB::bind_method(D_METHOD("_update_scrollbar_position"), &ScrollContainer::_update_scrollbar_position);
- ClassDB::bind_method(D_METHOD("set_h_scroll", "val"), &ScrollContainer::set_h_scroll);
+ ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &ScrollContainer::set_h_scroll);
ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
- ClassDB::bind_method(D_METHOD("set_v_scroll", "val"), &ScrollContainer::set_v_scroll);
+ ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);
ClassDB::bind_method(D_METHOD("get_v_scroll"), &ScrollContainer::get_v_scroll);
+ ClassDB::bind_method(D_METHOD("set_deadzone", "deadzone"), &ScrollContainer::set_deadzone);
+ ClassDB::bind_method(D_METHOD("get_deadzone"), &ScrollContainer::get_deadzone);
+
+ ADD_SIGNAL(MethodInfo("scroll_started"));
+ ADD_SIGNAL(MethodInfo("scroll_ended"));
ADD_GROUP("Scroll", "scroll_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal"), "set_enable_h_scroll", "is_h_scroll_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical"), "set_enable_v_scroll", "is_v_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone");
+
+ GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
};
ScrollContainer::ScrollContainer() {
@@ -487,8 +527,11 @@ ScrollContainer::ScrollContainer() {
drag_speed = Vector2();
drag_touching = false;
drag_touching_deaccel = false;
+ beyond_deadzone = false;
scroll_h = true;
scroll_v = true;
+ deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone");
+
set_clip_contents(true);
};
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index 2c5d60de6c..3fe1ed447a 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCROLL_CONTAINER_H
#define SCROLL_CONTAINER_H
@@ -55,10 +56,13 @@ class ScrollContainer : public Container {
bool drag_touching;
bool drag_touching_deaccel;
bool click_handled;
+ bool beyond_deadzone;
bool scroll_h;
bool scroll_v;
+ int deadzone;
+
void _cancel_drag();
protected:
@@ -85,6 +89,9 @@ public:
void set_enable_v_scroll(bool p_enable);
bool is_v_scroll_enabled() const;
+ int get_deadzone() const;
+ void set_deadzone(int p_deadzone);
+
virtual bool clips_input() const;
virtual String get_configuration_warning() const;
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index 55d837458a..cd0b06da81 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "separator.h"
Size2 Separator::get_minimum_size() const {
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index be2f1e8e77..7949c7ca9b 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SEPARATOR_H
#define SEPARATOR_H
diff --git a/scene/gui/shortcut.cpp b/scene/gui/shortcut.cpp
index f37410e77b..36490cf254 100644
--- a/scene/gui/shortcut.cpp
+++ b/scene/gui/shortcut.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "shortcut.h"
#include "os/keyboard.h"
diff --git a/scene/gui/shortcut.h b/scene/gui/shortcut.h
index 8d85bb920f..f9240642bf 100644
--- a/scene/gui/shortcut.h
+++ b/scene/gui/shortcut.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SHORTCUT_H
#define SHORTCUT_H
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 70b8616af1..46215c9277 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "slider.h"
#include "os/keyboard.h"
@@ -117,28 +118,14 @@ void Slider::_gui_input(Ref<InputEvent> p_event) {
return;
set_value(get_value() - (custom_step >= 0 ? custom_step : get_step()));
accept_event();
+ } else if (p_event->is_action("ui_home") && p_event->is_pressed()) {
- } else {
-
- Ref<InputEventKey> k = p_event;
-
- if (!k.is_valid() || !k->is_pressed())
- return;
-
- switch (k->get_scancode()) {
-
- case KEY_HOME: {
-
- set_value(get_min());
- accept_event();
- } break;
- case KEY_END: {
-
- set_value(get_max());
- accept_event();
+ set_value(get_min());
+ accept_event();
+ } else if (p_event->is_action("ui_end") && p_event->is_pressed()) {
- } break;
- }
+ set_value(get_max());
+ accept_event();
}
}
}
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 95ae429d63..e77a0b7423 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SLIDER_H
#define SLIDER_H
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 05f2809bfc..145981d498 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "spin_box.h"
#include "os/input.h"
@@ -184,17 +185,22 @@ void SpinBox::_line_edit_focus_exit() {
_text_entered(line_edit->get_text());
}
+inline void SpinBox::_adjust_width_for_icon(const Ref<Texture> icon) {
+
+ int w = icon->get_width();
+ if (w != last_w) {
+ line_edit->set_margin(MARGIN_RIGHT, -w);
+ last_w = w;
+ }
+}
+
void SpinBox::_notification(int p_what) {
if (p_what == NOTIFICATION_DRAW) {
Ref<Texture> updown = get_icon("updown");
- int w = updown->get_width();
- if (w != last_w) {
- line_edit->set_margin(MARGIN_RIGHT, -w);
- last_w = w;
- }
+ _adjust_width_for_icon(updown);
RID ci = get_canvas_item();
Size2i size = get_size();
@@ -206,6 +212,7 @@ void SpinBox::_notification(int p_what) {
//_value_changed(0);
} else if (p_what == NOTIFICATION_ENTER_TREE) {
+ _adjust_width_for_icon(get_icon("updown"));
_value_changed(0);
}
}
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 0c562bd744..8863f44bef 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPIN_BOX_H
#define SPIN_BOX_H
@@ -61,6 +62,8 @@ class SpinBox : public Range {
void _line_edit_focus_exit();
+ inline void _adjust_width_for_icon(const Ref<Texture> icon);
+
protected:
void _gui_input(const Ref<InputEvent> &p_event);
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 4420a936d2..c38c411333 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,18 +27,12 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "split_container.h"
#include "label.h"
#include "margin_container.h"
-struct _MinSizeCache {
-
- int min_size;
- bool will_stretch;
- int final_size;
-};
-
Control *SplitContainer::_getch(int p_idx) const {
int idx = 0;
@@ -60,136 +54,69 @@ Control *SplitContainer::_getch(int p_idx) const {
}
void SplitContainer::_resort() {
-
- /** First pass, determine minimum size AND amount of stretchable elements */
-
int axis = vertical ? 1 : 0;
- bool has_first = _getch(0);
- bool has_second = _getch(1);
+ Control *first = _getch(0);
+ Control *second = _getch(1);
- if (!has_first && !has_second) {
- return;
- } else if (!(has_first && has_second)) {
- if (has_first)
+ // If we have only one element
+ if (!first || !second) {
+ if (first) {
fit_child_in_rect(_getch(0), Rect2(Point2(), get_size()));
- else
+ } else if (second) {
fit_child_in_rect(_getch(1), Rect2(Point2(), get_size()));
-
+ }
return;
}
- Control *first = _getch(0);
- Control *second = _getch(1);
-
- bool ratiomode = false;
- bool expand_first_mode = false;
-
+ // Determine expanded children
+ bool first_expanded = false;
+ bool second_expanded = false;
if (vertical) {
-
- ratiomode = first->get_v_size_flags() & SIZE_EXPAND && second->get_v_size_flags() & SIZE_EXPAND;
- expand_first_mode = first->get_v_size_flags() & SIZE_EXPAND && !(second->get_v_size_flags() & SIZE_EXPAND);
+ first_expanded = first->get_v_size_flags() & SIZE_EXPAND;
+ second_expanded = second->get_v_size_flags() & SIZE_EXPAND;
} else {
-
- ratiomode = first->get_h_size_flags() & SIZE_EXPAND && second->get_h_size_flags() & SIZE_EXPAND;
- expand_first_mode = first->get_h_size_flags() & SIZE_EXPAND && !(second->get_h_size_flags() & SIZE_EXPAND);
+ first_expanded = first->get_h_size_flags() & SIZE_EXPAND;
+ second_expanded = second->get_h_size_flags() & SIZE_EXPAND;
}
- int sep = get_constant("separation");
+ // Determine the separation between items
Ref<Texture> g = get_icon("grabber");
-
+ int sep = get_constant("separation");
if (dragger_visibility == DRAGGER_HIDDEN_COLLAPSED) {
sep = 0;
} else {
sep = MAX(sep, vertical ? g->get_height() : g->get_width());
}
- int total = vertical ? get_size().height : get_size().width;
-
- total -= sep;
-
- int minimum = 0;
-
+ // Compute the minimum size
Size2 ms_first = first->get_combined_minimum_size();
Size2 ms_second = second->get_combined_minimum_size();
- if (vertical) {
+ float ratio = first->get_stretch_ratio() / (first->get_stretch_ratio() + second->get_stretch_ratio());
- minimum = ms_first.height + ms_second.height;
+ int no_offset_middle_sep = 0;
+ if (first_expanded && second_expanded) {
+ no_offset_middle_sep = get_size()[axis] * ratio - sep / 2;
+ } else if (first_expanded) {
+ no_offset_middle_sep = get_size()[axis] - ms_second[axis] - sep;
} else {
-
- minimum = ms_first.width + ms_second.width;
+ no_offset_middle_sep = ms_first[axis];
}
- int available = total - minimum;
- if (available < 0)
- available = 0;
-
- middle_sep = 0;
-
- if (collapsed) {
-
- if (ratiomode) {
-
- int first_ratio = first->get_stretch_ratio();
- int second_ratio = second->get_stretch_ratio();
-
- float ratio = float(first_ratio) / (first_ratio + second_ratio);
-
- middle_sep = ms_first[axis] + available * ratio;
-
- } else if (expand_first_mode) {
-
- middle_sep = get_size()[axis] - ms_second[axis] - sep;
-
- } else {
-
- middle_sep = ms_first[axis];
- }
-
- } else if (ratiomode) {
-
- int first_ratio = first->get_stretch_ratio();
- int second_ratio = second->get_stretch_ratio();
-
- float ratio = float(first_ratio) / (first_ratio + second_ratio);
-
- if (expand_ofs < -(available * ratio))
- expand_ofs = -(available * ratio);
- else if (expand_ofs > (available * (1.0 - ratio)))
- expand_ofs = (available * (1.0 - ratio));
-
- middle_sep = ms_first[axis] + available * ratio + expand_ofs;
-
- } else if (expand_first_mode) {
-
- if (expand_ofs > 0)
- expand_ofs = 0;
-
- if (expand_ofs < -available)
- expand_ofs = -available;
-
- middle_sep = get_size()[axis] - ms_second[axis] - sep + expand_ofs;
-
- } else {
-
- if (expand_ofs < 0)
- expand_ofs = 0;
-
- if (expand_ofs > available)
- expand_ofs = available;
-
- middle_sep = ms_first[axis] + expand_ofs;
+ middle_sep = no_offset_middle_sep;
+ middle_sep += (collapsed) ? 0 : split_offset;
+ middle_sep = MIN(middle_sep, get_size()[axis] - ms_second[axis] - sep);
+ middle_sep = MAX(middle_sep, ms_first[axis]);
+ if (!collapsed) {
+ split_offset = middle_sep - no_offset_middle_sep;
}
if (vertical) {
-
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(get_size().width, middle_sep)));
int sofs = middle_sep + sep;
fit_child_in_rect(second, Rect2(Point2(0, sofs), Size2(get_size().width, get_size().height - sofs)));
-
} else {
-
fit_child_in_rect(first, Rect2(Point2(0, 0), Size2(middle_sep, get_size().height)));
int sofs = middle_sep + sep;
fit_child_in_rect(second, Rect2(Point2(sofs, 0), Size2(get_size().width - sofs, get_size().height)));
@@ -246,10 +173,12 @@ void SplitContainer::_notification(int p_what) {
_resort();
} break;
case NOTIFICATION_MOUSE_ENTER: {
+
mouse_inside = true;
update();
} break;
case NOTIFICATION_MOUSE_EXIT: {
+
mouse_inside = false;
update();
} break;
@@ -260,22 +189,17 @@ void SplitContainer::_notification(int p_what) {
if (collapsed || (!mouse_inside && get_constant("autohide")))
return;
+
int sep = dragger_visibility != DRAGGER_HIDDEN_COLLAPSED ? get_constant("separation") : 0;
Ref<Texture> tex = get_icon("grabber");
Size2 size = get_size();
- if (vertical) {
+ if (dragger_visibility == DRAGGER_VISIBLE) {
- //draw_style_box( get_stylebox("bg"), Rect2(0,middle_sep,get_size().width,sep));
- if (dragger_visibility == DRAGGER_VISIBLE)
+ if (vertical)
draw_texture(tex, Point2i((size.x - tex->get_width()) / 2, middle_sep + (sep - tex->get_height()) / 2));
-
- } else {
-
- //draw_style_box( get_stylebox("bg"), Rect2(middle_sep,0,sep,get_size().height));
- if (dragger_visibility == DRAGGER_VISIBLE)
+ else
draw_texture(tex, Point2i(middle_sep + (sep - tex->get_width()) / 2, (size.y - tex->get_height()) / 2));
}
-
} break;
}
}
@@ -292,21 +216,24 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
if (mb->get_button_index() == BUTTON_LEFT) {
if (mb->is_pressed()) {
+
int sep = get_constant("separation");
if (vertical) {
if (mb->get_position().y > middle_sep && mb->get_position().y < middle_sep + sep) {
+
dragging = true;
drag_from = mb->get_position().y;
- drag_ofs = expand_ofs;
+ drag_ofs = split_offset;
}
} else {
if (mb->get_position().x > middle_sep && mb->get_position().x < middle_sep + sep) {
+
dragging = true;
drag_from = mb->get_position().x;
- drag_ofs = expand_ofs;
+ drag_ofs = split_offset;
}
}
} else {
@@ -318,36 +245,31 @@ void SplitContainer::_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
- if (mm.is_valid()) {
-
- if (dragging) {
+ if (mm.is_valid() && dragging) {
- expand_ofs = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
- queue_sort();
- emit_signal("dragged", get_split_offset());
- }
+ split_offset = drag_ofs + ((vertical ? mm->get_position().y : mm->get_position().x) - drag_from);
+ queue_sort();
+ emit_signal("dragged", get_split_offset());
}
}
Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const {
- if (collapsed)
- return Control::get_cursor_shape(p_pos);
-
if (dragging)
return (vertical ? CURSOR_VSIZE : CURSOR_HSIZE);
- int sep = get_constant("separation");
+ if (!collapsed && _getch(0) && _getch(1) && dragger_visibility == DRAGGER_VISIBLE) {
- if (vertical) {
+ int sep = get_constant("separation");
- if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep) {
- return CURSOR_VSIZE;
- }
- } else {
+ if (vertical) {
- if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep) {
- return CURSOR_HSIZE;
+ if (p_pos.y > middle_sep && p_pos.y < middle_sep + sep)
+ return CURSOR_VSIZE;
+ } else {
+
+ if (p_pos.x > middle_sep && p_pos.x < middle_sep + sep)
+ return CURSOR_HSIZE;
}
}
@@ -356,21 +278,23 @@ Control::CursorShape SplitContainer::get_cursor_shape(const Point2 &p_pos) const
void SplitContainer::set_split_offset(int p_offset) {
- if (expand_ofs == p_offset)
+ if (split_offset == p_offset)
return;
- expand_ofs = p_offset;
+
+ split_offset = p_offset;
queue_sort();
}
int SplitContainer::get_split_offset() const {
- return expand_ofs;
+ return split_offset;
}
void SplitContainer::set_collapsed(bool p_collapsed) {
if (collapsed == p_collapsed)
return;
+
collapsed = p_collapsed;
queue_sort();
}
@@ -418,7 +342,7 @@ void SplitContainer::_bind_methods() {
SplitContainer::SplitContainer(bool p_vertical) {
mouse_inside = false;
- expand_ofs = 0;
+ split_offset = 0;
middle_sep = 0;
vertical = p_vertical;
dragging = false;
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index c7a484c4c5..321f7fd3b7 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPLIT_CONTAINER_H
#define SPLIT_CONTAINER_H
@@ -45,7 +46,7 @@ public:
private:
bool vertical;
- int expand_ofs;
+ int split_offset;
int middle_sep;
bool dragging;
int drag_from;
@@ -88,7 +89,7 @@ class HSplitContainer : public SplitContainer {
public:
HSplitContainer() :
- SplitContainer(false) { set_default_cursor_shape(CURSOR_HSPLIT); }
+ SplitContainer(false) {}
};
class VSplitContainer : public SplitContainer {
@@ -97,7 +98,7 @@ class VSplitContainer : public SplitContainer {
public:
VSplitContainer() :
- SplitContainer(true) { set_default_cursor_shape(CURSOR_VSPLIT); }
+ SplitContainer(true) {}
};
#endif // SPLIT_CONTAINER_H
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index f2a2d862de..0363dd44c2 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,9 +27,13 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tab_container.h"
#include "message_queue.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/label.h"
+#include "scene/gui/texture_rect.h"
int TabContainer::_get_top_margin() const {
@@ -473,21 +477,159 @@ void TabContainer::remove_child_notify(Node *p_child) {
Control::remove_child_notify(p_child);
+ call_deferred("_update_current_tab");
+
+ p_child->disconnect("renamed", this, "_child_renamed_callback");
+
+ update();
+}
+
+void TabContainer::_update_current_tab() {
+
int tc = get_tab_count();
- if (current == tc - 1) {
- current--;
- if (current < 0)
- current = 0;
- else {
- call_deferred("set_current_tab", current);
+ if (current >= tc)
+ current = tc - 1;
+ if (current < 0)
+ current = 0;
+ else
+ set_current_tab(current);
+}
+
+Variant TabContainer::get_drag_data(const Point2 &p_point) {
+
+ if (!drag_to_rearrange_enabled)
+ return Variant();
+
+ int tab_over = get_tab_idx_at_point(p_point);
+
+ if (tab_over < 0)
+ return Variant();
+
+ HBoxContainer *drag_preview = memnew(HBoxContainer);
+
+ Ref<Texture> icon = get_tab_icon(tab_over);
+ if (!icon.is_null()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(icon);
+ drag_preview->add_child(tf);
+ }
+ Label *label = memnew(Label(get_tab_title(tab_over)));
+ drag_preview->add_child(label);
+ set_drag_preview(drag_preview);
+
+ Dictionary drag_data;
+ drag_data["type"] = "tabc_element";
+ drag_data["tabc_element"] = tab_over;
+ drag_data["from_path"] = get_path();
+ return drag_data;
+}
+
+bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
+
+ if (!drag_to_rearrange_enabled)
+ return false;
+
+ Dictionary d = p_data;
+ if (!d.has("type"))
+ return false;
+
+ if (String(d["type"]) == "tabc_element") {
+
+ NodePath from_path = d["from_path"];
+ NodePath to_path = get_path();
+ if (from_path == to_path) {
+ return true;
+ } else if (get_tabs_rearrange_group() != -1) {
+ // drag and drop between other TabContainers
+ Node *from_node = get_node(from_path);
+ TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
+ if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
+ return true;
+ }
}
}
+ return false;
+}
- p_child->disconnect("renamed", this, "_child_renamed_callback");
+void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) {
+ if (!drag_to_rearrange_enabled)
+ return;
+
+ int hover_now = get_tab_idx_at_point(p_point);
+
+ Dictionary d = p_data;
+ if (!d.has("type"))
+ return;
+
+ if (String(d["type"]) == "tabc_element") {
+
+ int tab_from_id = d["tabc_element"];
+ NodePath from_path = d["from_path"];
+ NodePath to_path = get_path();
+ if (from_path == to_path) {
+ if (hover_now < 0)
+ hover_now = get_tab_count() - 1;
+ move_child(get_tab_control(tab_from_id), hover_now);
+ set_current_tab(hover_now);
+ } else if (get_tabs_rearrange_group() != -1) {
+ // drag and drop between TabContainers
+ Node *from_node = get_node(from_path);
+ TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
+ if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
+ Control *moving_tabc = from_tabc->get_tab_control(tab_from_id);
+ from_tabc->remove_child(moving_tabc);
+ add_child(moving_tabc);
+ if (hover_now < 0)
+ hover_now = get_tab_count() - 1;
+ move_child(moving_tabc, hover_now);
+ set_current_tab(hover_now);
+ emit_signal("tab_changed", hover_now);
+ }
+ }
+ }
update();
}
+int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const {
+
+ if (get_tab_count() == 0)
+ return -1;
+
+ // must be on tabs in the tab header area.
+ if (p_point.x < tabs_ofs_cache || p_point.y > _get_top_margin())
+ return -1;
+
+ Size2 size = get_size();
+ int right_ofs = 0;
+
+ if (popup) {
+ Ref<Texture> menu = get_icon("menu");
+ right_ofs += menu->get_width();
+ }
+ if (buttons_visible_cache) {
+ Ref<Texture> increment = get_icon("increment");
+ Ref<Texture> decrement = get_icon("decrement");
+ right_ofs += increment->get_width() + decrement->get_width();
+ }
+ if (p_point.x > size.width - right_ofs) {
+ return -1;
+ }
+
+ // get the tab at the point
+ Vector<Control *> tabs = _get_tabs();
+ int px = p_point.x;
+ px -= tabs_ofs_cache;
+ for (int i = first_tab_cache; i <= last_tab_cache; i++) {
+ int tab_width = _get_tab_width(i);
+ if (px < tab_width) {
+ return i;
+ }
+ px -= tab_width;
+ }
+ return -1;
+}
+
void TabContainer::set_tab_align(TabAlign p_align) {
ERR_FAIL_INDEX(p_align, 3);
@@ -496,6 +638,7 @@ void TabContainer::set_tab_align(TabAlign p_align) {
_change_notify("tab_align");
}
+
TabContainer::TabAlign TabContainer::get_tab_align() const {
return align;
@@ -639,6 +782,21 @@ Popup *TabContainer::get_popup() const {
return popup;
}
+void TabContainer::set_drag_to_rearrange_enabled(bool p_enabled) {
+ drag_to_rearrange_enabled = p_enabled;
+}
+
+bool TabContainer::get_drag_to_rearrange_enabled() const {
+ return drag_to_rearrange_enabled;
+}
+void TabContainer::set_tabs_rearrange_group(int p_group_id) {
+ tabs_rearrange_group = p_group_id;
+}
+
+int TabContainer::get_tabs_rearrange_group() const {
+ return tabs_rearrange_group;
+}
+
void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &TabContainer::_gui_input);
@@ -660,9 +818,14 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled);
ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup);
ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup);
+ ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabContainer::set_drag_to_rearrange_enabled);
+ ClassDB::bind_method(D_METHOD("get_drag_to_rearrange_enabled"), &TabContainer::get_drag_to_rearrange_enabled);
+ ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group);
+ ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group);
ClassDB::bind_method(D_METHOD("_child_renamed_callback"), &TabContainer::_child_renamed_callback);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
+ ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab")));
@@ -671,6 +834,7 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
BIND_ENUM_CONSTANT(ALIGN_LEFT);
BIND_ENUM_CONSTANT(ALIGN_CENTER);
@@ -689,4 +853,6 @@ TabContainer::TabContainer() {
align = ALIGN_CENTER;
tabs_visible = true;
popup = NULL;
+ drag_to_rearrange_enabled = false;
+ tabs_rearrange_group = -1;
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index a36c4f3790..1afe5f7541 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TAB_CONTAINER_H
#define TAB_CONTAINER_H
@@ -57,10 +58,13 @@ private:
Control *_get_tab(int p_idx) const;
int _get_top_margin() const;
Popup *popup;
+ bool drag_to_rearrange_enabled;
+ int tabs_rearrange_group;
Vector<Control *> _get_tabs() const;
int _get_tab_width(int p_index) const;
void _on_theme_changed();
+ void _update_current_tab();
protected:
void _child_renamed_callback();
@@ -69,6 +73,11 @@ protected:
virtual void add_child_notify(Node *p_child);
virtual void remove_child_notify(Node *p_child);
+ Variant get_drag_data(const Point2 &p_point);
+ bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
+ void drop_data(const Point2 &p_point, const Variant &p_data);
+ int get_tab_idx_at_point(const Point2 &p_point) const;
+
static void _bind_methods();
public:
@@ -102,6 +111,11 @@ public:
void set_popup(Node *p_popup);
Popup *get_popup() const;
+ void set_drag_to_rearrange_enabled(bool p_enabled);
+ bool get_drag_to_rearrange_enabled() const;
+ void set_tabs_rearrange_group(int p_group_id);
+ int get_tabs_rearrange_group() const;
+
TabContainer();
};
diff --git a/scene/gui/tabs.cpp b/scene/gui/tabs.cpp
index 1fb0f84223..b114264de1 100644
--- a/scene/gui/tabs.cpp
+++ b/scene/gui/tabs.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,9 +27,13 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tabs.h"
#include "message_queue.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/label.h"
+#include "scene/gui/texture_rect.h"
Size2 Tabs::get_minimum_size() const {
@@ -623,20 +627,105 @@ void Tabs::remove_tab(int p_idx) {
Variant Tabs::get_drag_data(const Point2 &p_point) {
- return get_tab_idx_at_point(p_point);
+ if (!drag_to_rearrange_enabled)
+ return Variant();
+
+ int tab_over = get_tab_idx_at_point(p_point);
+
+ if (tab_over < 0)
+ return Variant();
+
+ HBoxContainer *drag_preview = memnew(HBoxContainer);
+
+ if (!tabs[tab_over].icon.is_null()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(tabs[tab_over].icon);
+ drag_preview->add_child(tf);
+ }
+ Label *label = memnew(Label(tabs[tab_over].text));
+ drag_preview->add_child(label);
+ if (!tabs[tab_over].right_button.is_null()) {
+ TextureRect *tf = memnew(TextureRect);
+ tf->set_texture(tabs[tab_over].right_button);
+ drag_preview->add_child(tf);
+ }
+ set_drag_preview(drag_preview);
+
+ Dictionary drag_data;
+ drag_data["type"] = "tab_element";
+ drag_data["tab_element"] = tab_over;
+ drag_data["from_path"] = get_path();
+ return drag_data;
}
bool Tabs::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
- return get_tab_idx_at_point(p_point) > -1;
+ if (!drag_to_rearrange_enabled)
+ return false;
+
+ Dictionary d = p_data;
+ if (!d.has("type"))
+ return false;
+
+ if (String(d["type"]) == "tab_element") {
+
+ NodePath from_path = d["from_path"];
+ NodePath to_path = get_path();
+ if (from_path == to_path) {
+ return true;
+ } else if (get_tabs_rearrange_group() != -1) {
+ // drag and drop between other Tabs
+ Node *from_node = get_node(from_path);
+ Tabs *from_tabs = Object::cast_to<Tabs>(from_node);
+ if (from_tabs && from_tabs->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
+ return true;
+ }
+ }
+ }
+ return false;
}
void Tabs::drop_data(const Point2 &p_point, const Variant &p_data) {
+ if (!drag_to_rearrange_enabled)
+ return;
+
int hover_now = get_tab_idx_at_point(p_point);
- ERR_FAIL_INDEX(hover_now, tabs.size());
- emit_signal("reposition_active_tab_request", hover_now);
+ Dictionary d = p_data;
+ if (!d.has("type"))
+ return;
+
+ if (String(d["type"]) == "tab_element") {
+
+ int tab_from_id = d["tab_element"];
+ NodePath from_path = d["from_path"];
+ NodePath to_path = get_path();
+ if (from_path == to_path) {
+ if (hover_now < 0)
+ hover_now = get_tab_count() - 1;
+ move_tab(tab_from_id, hover_now);
+ emit_signal("reposition_active_tab_request", hover_now);
+ set_current_tab(hover_now);
+ } else if (get_tabs_rearrange_group() != -1) {
+ // drag and drop between Tabs
+ Node *from_node = get_node(from_path);
+ Tabs *from_tabs = Object::cast_to<Tabs>(from_node);
+ if (from_tabs && from_tabs->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
+ if (tab_from_id >= from_tabs->get_tab_count())
+ return;
+ Tab moving_tab = from_tabs->tabs[tab_from_id];
+ if (hover_now < 0)
+ hover_now = get_tab_count();
+ tabs.insert(hover_now, moving_tab);
+ from_tabs->remove_tab(tab_from_id);
+ set_current_tab(hover_now);
+ emit_signal("tab_changed", hover_now);
+ _update_cache();
+ }
+ }
+ }
+ update();
}
int Tabs::get_tab_idx_at_point(const Point2 &p_point) const {
@@ -816,6 +905,21 @@ bool Tabs::get_scrolling_enabled() const {
return scrolling_enabled;
}
+void Tabs::set_drag_to_rearrange_enabled(bool p_enabled) {
+ drag_to_rearrange_enabled = p_enabled;
+}
+
+bool Tabs::get_drag_to_rearrange_enabled() const {
+ return drag_to_rearrange_enabled;
+}
+void Tabs::set_tabs_rearrange_group(int p_group_id) {
+ tabs_rearrange_group = p_group_id;
+}
+
+int Tabs::get_tabs_rearrange_group() const {
+ return tabs_rearrange_group;
+}
+
void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("_gui_input"), &Tabs::_gui_input);
@@ -841,6 +945,10 @@ void Tabs::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_close_display_policy"), &Tabs::get_tab_close_display_policy);
ClassDB::bind_method(D_METHOD("set_scrolling_enabled", "enabled"), &Tabs::set_scrolling_enabled);
ClassDB::bind_method(D_METHOD("get_scrolling_enabled"), &Tabs::get_scrolling_enabled);
+ ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &Tabs::set_drag_to_rearrange_enabled);
+ ClassDB::bind_method(D_METHOD("get_drag_to_rearrange_enabled"), &Tabs::get_drag_to_rearrange_enabled);
+ ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &Tabs::set_tabs_rearrange_group);
+ ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &Tabs::get_tabs_rearrange_group);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("right_button_pressed", PropertyInfo(Variant::INT, "tab")));
@@ -850,8 +958,10 @@ void Tabs::_bind_methods() {
ADD_SIGNAL(MethodInfo("tab_clicked", PropertyInfo(Variant::INT, "tab")));
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
BIND_ENUM_CONSTANT(ALIGN_LEFT);
BIND_ENUM_CONSTANT(ALIGN_CENTER);
@@ -880,4 +990,8 @@ Tabs::Tabs() {
min_width = 0;
scrolling_enabled = true;
+ buttons_visible = false;
+ hover = -1;
+ drag_to_rearrange_enabled = false;
+ tabs_rearrange_group = -1;
}
diff --git a/scene/gui/tabs.h b/scene/gui/tabs.h
index 4eb6be3435..3b38e7f2cb 100644
--- a/scene/gui/tabs.h
+++ b/scene/gui/tabs.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TABS_H
#define TABS_H
@@ -89,6 +90,8 @@ private:
int hover; // hovered tab
int min_width;
bool scrolling_enabled;
+ bool drag_to_rearrange_enabled;
+ int tabs_rearrange_group;
int get_tab_width(int p_idx) const;
void _ensure_no_over_offset();
@@ -142,6 +145,11 @@ public:
void set_scrolling_enabled(bool p_enabled);
bool get_scrolling_enabled() const;
+ void set_drag_to_rearrange_enabled(bool p_enabled);
+ bool get_drag_to_rearrange_enabled() const;
+ void set_tabs_rearrange_group(int p_group_id);
+ int get_tabs_rearrange_group() const;
+
void ensure_tab_visible(int p_idx);
void set_min_width(int p_width);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index e5169089f2..55a650ff12 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "text_edit.h"
#include "message_queue.h"
@@ -42,14 +43,14 @@
#define TAB_PIXELS
-static bool _is_text_char(CharType c) {
+inline bool _is_symbol(CharType c) {
- return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
+ return is_symbol(c);
}
-static bool _is_symbol(CharType c) {
+static bool _is_text_char(CharType c) {
- return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' ');
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static bool _is_whitespace(CharType c) {
@@ -116,7 +117,6 @@ void TextEdit::Text::set_indent_size(int p_indent_size) {
void TextEdit::Text::_update_line_cache(int p_line) const {
int w = 0;
- int tab_w = font->get_char_size(' ').width * indent_size;
int len = text[p_line].data.length();
const CharType *str = text[p_line].data.c_str();
@@ -124,22 +124,13 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
//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;
- }
+ w += get_char_width(str[i], str[i + 1], w);
}
text[p_line].width_cache = w;
+ text[p_line].wrap_amount_cache = -1;
+
//update regions
text[p_line].region_info.clear();
@@ -183,6 +174,7 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
cri.region = j;
text[p_line].region_info[i] = cri;
i += lr - 1;
+
break;
}
@@ -210,13 +202,14 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
cri.region = j;
text[p_line].region_info[i] = cri;
i += lr - 1;
+
break;
}
}
}
}
-const Map<int, TextEdit::Text::ColorRegionInfo> &TextEdit::Text::get_color_region_info(int p_line) {
+const Map<int, TextEdit::Text::ColorRegionInfo> &TextEdit::Text::get_color_region_info(int p_line) const {
static Map<int, ColorRegionInfo> cri;
ERR_FAIL_INDEX_V(p_line, text.size(), cri);
@@ -239,10 +232,32 @@ int TextEdit::Text::get_line_width(int p_line) const {
return text[p_line].width_cache;
}
-void TextEdit::Text::clear_caches() {
+void TextEdit::Text::set_line_wrap_amount(int p_line, int p_wrap_amount) const {
+
+ ERR_FAIL_INDEX(p_line, text.size());
+
+ text[p_line].wrap_amount_cache = p_wrap_amount;
+}
+
+int TextEdit::Text::get_line_wrap_amount(int p_line) const {
- for (int i = 0; i < text.size(); i++)
+ ERR_FAIL_INDEX_V(p_line, text.size(), -1);
+
+ return text[p_line].wrap_amount_cache;
+}
+
+void TextEdit::Text::clear_width_cache() {
+
+ for (int i = 0; i < text.size(); i++) {
text[i].width_cache = -1;
+ }
+}
+
+void TextEdit::Text::clear_wrap_cache() {
+
+ for (int i = 0; i < text.size(); i++) {
+ text[i].wrap_amount_cache = -1;
+ }
}
void TextEdit::Text::clear() {
@@ -267,6 +282,7 @@ 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].wrap_amount_cache = -1;
text[p_line].data = p_text;
}
@@ -277,6 +293,7 @@ void TextEdit::Text::insert(int p_at, const String &p_text) {
line.breakpoint = false;
line.hidden = false;
line.width_cache = -1;
+ line.wrap_amount_cache = -1;
line.data = p_text;
text.insert(p_at, line);
}
@@ -285,6 +302,25 @@ void TextEdit::Text::remove(int p_at) {
text.remove(p_at);
}
+int TextEdit::Text::get_char_width(CharType c, CharType next_c, int px) const {
+
+ int tab_w = font->get_char_size(' ').width * indent_size;
+ int w = 0;
+
+ if (c == '\t') {
+
+ int left = px % tab_w;
+ if (left == 0)
+ w = tab_w;
+ else
+ w = tab_w - px % tab_w; // is right...
+ } else {
+
+ w = font->get_char_size(c, next_c).width;
+ }
+ return w;
+}
+
void TextEdit::_update_scrollbars() {
Size2 size = get_size();
@@ -299,9 +335,12 @@ void TextEdit::_update_scrollbars() {
int hscroll_rows = ((hmin.height - 1) / get_row_height()) + 1;
int visible_rows = get_visible_rows();
- int num_rows = MAX(visible_rows, num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs)));
- int total_rows = (is_hiding_enabled() ? get_total_unhidden_rows() : text.size());
+ int first_vis_line = get_first_visible_line();
+ int wi;
+ int num_rows = MAX(visible_rows, num_lines_from_rows(first_vis_line, cursor.wrap_ofs, visible_rows, wi));
+
+ int total_rows = get_total_visible_rows();
if (scroll_past_end_of_file_enabled) {
total_rows += visible_rows - 1;
}
@@ -347,28 +386,24 @@ void TextEdit::_update_scrollbars() {
if (use_vscroll) {
v_scroll->show();
- v_scroll->set_max(total_rows);
- v_scroll->set_page(visible_rows);
+ v_scroll->set_max(total_rows + get_visible_rows_offset());
+ v_scroll->set_page(visible_rows + get_visible_rows_offset());
if (smooth_scroll_enabled) {
v_scroll->set_step(0.25);
} else {
v_scroll->set_step(1);
}
-
- update_line_scroll_pos();
- if (fabs(v_scroll->get_value() - get_line_scroll_pos()) >= 1) {
- cursor.line_ofs += v_scroll->get_value() - get_line_scroll_pos();
- }
+ set_v_scroll(get_v_scroll());
} else {
cursor.line_ofs = 0;
- line_scroll_pos = 0;
+ cursor.wrap_ofs = 0;
v_scroll->set_value(0);
v_scroll->hide();
}
- if (use_hscroll) {
+ if (use_hscroll && !is_wrap_enabled()) {
h_scroll->show();
h_scroll->set_max(total_width);
@@ -419,8 +454,8 @@ void TextEdit::_update_selection_mode_pointer() {
select(selection.selecting_line, selection.selecting_column, row, col);
- cursor_set_line(row);
- cursor_set_column(col);
+ cursor_set_line(row, false);
+ cursor_set_column(col, false);
update();
click_select_held->start();
@@ -454,7 +489,7 @@ void TextEdit::_update_selection_mode_word() {
end += 1;
}
- // inital selection
+ // initial selection
if (!selection.active) {
select(row, beg, row, end);
selection.selecting_column = beg;
@@ -473,7 +508,7 @@ void TextEdit::_update_selection_mode_word() {
cursor_set_column(selection.to_column);
}
}
- cursor_set_line(row);
+ cursor_set_line(row, false);
update();
click_select_held->start();
@@ -488,15 +523,15 @@ void TextEdit::_update_selection_mode_line() {
col = 0;
if (row < selection.selecting_line) {
// cursor is above us
- cursor_set_line(row - 1);
+ cursor_set_line(row - 1, false);
selection.selecting_column = text[selection.selecting_line].length();
} else {
// cursor is below us
- cursor_set_line(row + 1);
+ cursor_set_line(row + 1, false);
selection.selecting_column = 0;
col = text[row].length();
}
- cursor_set_column(0);
+ cursor_set_column(0, false);
select(selection.selecting_line, selection.selecting_column, row, col);
update();
@@ -514,13 +549,13 @@ void TextEdit::_notification(int p_what) {
MessageQueue::get_singleton()->push_call(this, "_cursor_changed_emit");
if (text_changed_dirty)
MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
-
+ update_wrap_at();
} break;
case NOTIFICATION_RESIZED: {
cache.size = get_size();
- adjust_viewport_to_cursor();
-
+ _update_scrollbars();
+ update_wrap_at();
} break;
case NOTIFICATION_THEME_CHANGED: {
@@ -536,26 +571,25 @@ void TextEdit::_notification(int p_what) {
draw_caret = false;
update();
} break;
- case NOTIFICATION_PHYSICS_PROCESS: {
- if (scrolling && v_scroll->get_value() != target_v_scroll) {
- double target_y = target_v_scroll - v_scroll->get_value();
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+ if (scrolling && get_v_scroll() != target_v_scroll) {
+ double target_y = target_v_scroll - get_v_scroll();
double dist = sqrt(target_y * target_y);
double vel = ((target_y / dist) * v_scroll_speed) * get_physics_process_delta_time();
if (Math::abs(vel) >= dist) {
- v_scroll->set_value(target_v_scroll);
+ set_v_scroll(target_v_scroll);
scrolling = false;
- set_physics_process(false);
+ set_physics_process_internal(false);
} else {
- v_scroll->set_value(v_scroll->get_value() + vel);
+ set_v_scroll(get_v_scroll() + vel);
}
} else {
scrolling = false;
- set_physics_process(false);
+ set_physics_process_internal(false);
}
} break;
case NOTIFICATION_DRAW: {
-
if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
draw_caret = false;
}
@@ -618,44 +652,10 @@ void TextEdit::_notification(int p_what) {
Color color = cache.font_color;
color.a *= readonly_alpha;
- int in_region = -1;
-
if (syntax_coloring) {
-
if (cache.background_color.a > 0.01) {
-
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), cache.background_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;
@@ -775,7 +775,6 @@ void TextEdit::_notification(int p_what) {
j--;
}
if (escaped) {
- j--;
cc = '\\';
continue;
}
@@ -804,18 +803,20 @@ void TextEdit::_notification(int p_what) {
}
}
- int deregion = 0; //force it to clear inrgion
Point2 cursor_pos;
// get the highlighted words
String highlighted_text = get_selection_text();
String line_num_padding = line_numbers_zero_padded ? "0" : " ";
- update_line_scroll_pos();
- int line = cursor.line_ofs - 1;
- // another row may be visible during smooth scrolling
+ int cursor_wrap_index = get_cursor_wrap_index();
+
+ FontDrawer drawer(cache.font, Color(1, 1, 1));
+
+ int line = get_first_visible_line() - 1;
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
+ draw_amount += times_line_wraps(line + 1);
for (int i = 0; i < draw_amount; i++) {
line++;
@@ -833,379 +834,360 @@ void TextEdit::_notification(int p_what) {
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;
+ const String &fullstr = text[line];
- int ofs_readonly = 0;
- int ofs_x = 0;
+ Map<int, HighlighterInfo> color_map;
+ if (syntax_coloring) {
+ color_map = _get_line_syntax_highlighting(line);
+ }
+ // ensure we at least use the font color
+ Color current_color = cache.font_color;
if (readonly) {
- ofs_readonly = cache.style_readonly->get_offset().y / 2;
- ofs_x = cache.style_readonly->get_offset().x / 2;
+ current_color.a *= readonly_alpha;
}
- int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly;
- if (smooth_scroll_enabled)
- ofs_y -= ((v_scroll->get_value() - get_line_scroll_pos()) * get_row_height());
- bool prev_is_char = false;
- bool prev_is_number = false;
- bool in_keyword = false;
bool underlined = false;
- bool in_word = false;
- bool in_function_name = false;
- bool in_member_variable = false;
- bool is_hex_notation = false;
- Color keyword_color;
- // check if line contains highlighted word
- int highlighted_text_col = -1;
- int search_text_col = -1;
+ int line_wrap_amount = times_line_wraps(line);
+ int last_wrap_column = 0;
+ Vector<String> wrap_rows = get_wrap_rows_text(line);
- if (!search_text.empty())
- search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0);
+ for (int line_wrap_index = 0; line_wrap_index < line_wrap_amount + 1; line_wrap_index++) {
+ if (line_wrap_index != 0) {
+ i++;
+ if (i >= draw_amount)
+ break;
+ }
- if (highlighted_text.length() != 0 && highlighted_text != search_text)
- highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
+ const String &str = wrap_rows[line_wrap_index];
+ int indent_px = line_wrap_index != 0 ? get_indent_level(line) * cache.font->get_char_size(' ').width : 0;
- const Map<int, Text::ColorRegionInfo> &cri_map = text.get_color_region_info(line);
+ if (line_wrap_index > 0)
+ last_wrap_column += wrap_rows[line_wrap_index - 1].length();
- if (text.is_marked(line)) {
+ int char_margin = xmargin_beg - cursor.x_ofs;
+ char_margin += indent_px;
+ int char_ofs = 0;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
- }
-
- if (str.length() == 0) {
- // draw line background if empty as we won't loop at at all
- if (line == cursor.line && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
+ int ofs_readonly = 0;
+ int ofs_x = 0;
+ if (readonly) {
+ ofs_readonly = cache.style_readonly->get_offset().y / 2;
+ ofs_x = cache.style_readonly->get_offset().x / 2;
}
- // give visual indication of empty selected line
- if (selection.active && line >= selection.from_line && line <= selection.to_line) {
- int char_w = cache.font->get_char_size(' ').width;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color);
- }
- } else {
- // if it has text, then draw current line marker in the margin, as line number ect will draw over it, draw the rest of line marker later.
- if (line == cursor.line && highlight_current_line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg, get_row_height()), cache.current_line_color);
- }
- }
+ int ofs_y = (i * get_row_height() + cache.line_spacing / 2) + ofs_readonly;
+ ofs_y -= cursor.wrap_ofs * get_row_height();
+ if (smooth_scroll_enabled)
+ ofs_y += (-get_v_scroll_offset()) * get_row_height();
- if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
-#ifdef TOOLS_ENABLED
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
-#else
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
-#endif
- }
+ // check if line contains highlighted word
+ int highlighted_text_col = -1;
+ int search_text_col = -1;
+ int highlighted_word_col = -1;
- // draw breakpoint marker
- if (text.is_breakpoint(line)) {
- if (draw_breakpoint_gutter) {
- int vertical_gap = (get_row_height() * 40) / 100;
- int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
- int marker_height = get_row_height() - (vertical_gap * 2);
- int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2);
- // no transparency on marker
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b));
- }
- }
+ if (!search_text.empty())
+ search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0);
- // draw fold markers
- if (draw_fold_gutter) {
- int horizontal_gap = (cache.fold_gutter_width * 30) / 100;
- int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w;
- if (is_folded(line)) {
- int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2;
- int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2;
- cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
- } else if (can_fold(line)) {
- int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3;
- int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2;
- cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
- }
- }
+ if (highlighted_text.length() != 0 && highlighted_text != search_text)
+ highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
- if (cache.line_number_w) {
- String fc = String::num(line + 1);
- while (fc.length() < line_number_char_count) {
- fc = line_num_padding + fc;
+ if (select_identifiers_enabled && highlighted_word.length() != 0) {
+ if (_is_char(highlighted_word[0])) {
+ highlighted_word_col = _get_column_pos_of_word(highlighted_word, fullstr, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, 0);
+ }
}
- cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color);
- }
- //loop through charcters in one line
- for (int j = 0; j < str.length(); j++) {
-
- //look for keyword
-
- if (deregion > 0) {
- deregion--;
- if (deregion == 0)
- in_region = -1;
+ if (text.is_marked(line)) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
}
- if (syntax_coloring && deregion == 0) {
-
- color = cache.font_color; //reset
- color.a *= readonly_alpha;
- //find keyword
- bool is_char = _is_text_char(str[j]);
- bool is_symbol = _is_symbol(str[j]);
- bool is_number = _is_number(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 (str.length() == 0) {
+ // draw line background if empty as we won't loop at at all
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
}
- // allow ABCDEF in hex notation
- if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) {
- is_number = true;
- } else {
- is_hex_notation = false;
+ // give visual indication of empty selected line
+ if (selection.active && line >= selection.from_line && line <= selection.to_line && char_margin >= xmargin_beg) {
+ int char_w = cache.font->get_char_size(' ').width;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, char_w, get_row_height()), cache.selection_color);
+ }
+ } else {
+ // if it has text, then draw current line marker in the margin, as line number etc will draw over it, draw the rest of line marker later.
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_beg, get_row_height()), cache.current_line_color);
}
+ }
- // check for dot or underscore or 'x' for hex notation in floating point number
- if ((str[j] == '.' || str[j] == 'x' || str[j] == '_') && !in_word && prev_is_number && !is_number) {
- is_number = true;
- is_symbol = false;
- is_char = false;
+ if (line_wrap_index == 0) {
+ // only do these if we are on the first wrapped part of a line
- if (str[j] == 'x' && str[j - 1] == '0') {
- is_hex_notation = true;
- }
+ if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
+#ifdef TOOLS_ENABLED
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
+#else
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
+#endif
}
- if (!in_word && _is_char(str[j]) && !is_number) {
- in_word = true;
+ // draw breakpoint marker
+ if (text.is_breakpoint(line)) {
+ if (draw_breakpoint_gutter) {
+ int vertical_gap = (get_row_height() * 40) / 100;
+ int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100;
+ int marker_height = get_row_height() - (vertical_gap * 2);
+ int marker_width = cache.breakpoint_gutter_width - (horizontal_gap * 2);
+ // no transparency on marker
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cache.style_normal->get_margin(MARGIN_LEFT) + horizontal_gap - 2, ofs_y + vertical_gap, marker_width, marker_height), Color(cache.breakpoint_color.r, cache.breakpoint_color.g, cache.breakpoint_color.b));
+ }
}
- if ((in_keyword || in_word) && !is_hex_notation) {
- is_number = false;
+ // draw fold markers
+ if (draw_fold_gutter) {
+ int horizontal_gap = (cache.fold_gutter_width * 30) / 100;
+ int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w;
+ if (is_folded(line)) {
+ int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2;
+ int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2;
+ cache.folded_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
+ } else if (can_fold(line)) {
+ int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3;
+ int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2;
+ cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs + ofs_x, ofs_y + yofs), cache.code_folding_color);
+ }
}
- if (is_symbol && str[j] != '.' && in_word) {
- in_word = false;
+ // draw line numbers
+ if (cache.line_number_w) {
+ String fc = String::num(line + 1);
+ while (fc.length() < line_number_char_count) {
+ fc = line_num_padding + fc;
+ }
+
+ cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + ofs_x, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color);
}
+ }
- if (is_symbol && cri_map.has(j)) {
+ //loop through characters in one line
+ for (int j = 0; j < str.length(); j++) {
- const Text::ColorRegionInfo &cri = cri_map[j];
+ if (syntax_coloring) {
+ if (color_map.has(last_wrap_column + j)) {
+ current_color = color_map[last_wrap_column + j].color;
+ if (readonly) {
+ current_color.a *= readonly_alpha;
+ }
+ }
+ color = current_color;
+ }
- if (in_region == -1) {
+ int char_w;
- if (!cri.end) {
+ //handle tabulator
+ char_w = text.get_char_width(str[j], str[j + 1], char_ofs);
- in_region = cri.region;
- }
- } else if (in_region == cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
+ if ((char_ofs + char_margin) < xmargin_beg) {
+ char_ofs += char_w;
- if (cri.end || color_regions[cri.region].eq) {
+ // line highlighting handle horizontal clipping
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
- deregion = color_regions[cri.region].eq ? color_regions[cri.region].begin_key.length() : color_regions[cri.region].end_key.length();
+ if (j == str.length() - 1) {
+ // end of line when last char is skipped
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ } else if ((char_ofs + char_margin) > xmargin_beg) {
+ // char next to margin is skipped
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, (char_ofs + char_margin) - (xmargin_beg + ofs_x), get_row_height()), cache.current_line_color);
}
}
+ continue;
}
- if (!is_char) {
- in_keyword = false;
- underlined = false;
+ if ((char_ofs + char_margin + char_w) >= xmargin_end) {
+ if (syntax_coloring)
+ continue;
+ else
+ break;
}
- if (in_region == -1 && !in_keyword && is_char && !prev_is_char) {
+ bool in_search_result = false;
- int to = j;
- while (to < str.length() && _is_text_char(str[to]))
- to++;
+ if (search_text_col != -1) {
+ // if we are at the end check for new search result on same line
+ if (j >= search_text_col + search_text.length())
+ search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j);
- uint32_t hash = String::hash(&str[j], to - j);
- StrRange range(&str[j], to - j);
+ in_search_result = j >= search_text_col && j < search_text_col + search_text.length();
- const Color *col = keywords.custom_getptr(range, hash);
-
- if (col) {
-
- in_keyword = true;
- keyword_color = *col;
- }
-
- if (select_identifiers_enabled && highlighted_word != String()) {
- if (highlighted_word == range) {
- underlined = true;
- }
+ if (in_search_result) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.search_result_color);
}
}
- if (!in_function_name && in_word && !in_keyword) {
+ //current line highlighting
+ bool in_selection = (selection.active && line >= selection.from_line && line <= selection.to_line && (line > selection.from_line || last_wrap_column + j >= selection.from_column) && (line < selection.to_line || last_wrap_column + j < selection.to_column));
- int k = j;
- while (k < str.length() && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
- k++;
+ if (line == cursor.line && cursor_wrap_index == line_wrap_index && highlight_current_line) {
+ // draw the wrap indent offset highlight
+ if (line_wrap_index != 0 && j == 0) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin - indent_px, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color);
}
-
- // check for space between name and bracket
- while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
- k++;
+ // if its the last char draw to end of the line
+ if (j == str.length() - 1) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
}
-
- if (str[k] == '(') {
- in_function_name = true;
+ // actual text
+ if (!in_selection) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
}
}
- if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) {
- int k = j;
- while (k > 0 && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
- k--;
- }
-
- if (str[k] == '.') {
- in_member_variable = true;
- }
+ if (in_selection) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color);
}
- if (is_symbol) {
- in_function_name = false;
- in_member_variable = false;
- }
-
- if (in_region >= 0)
- color = color_regions[in_region].color;
- else if (in_keyword)
- color = keyword_color;
- else if (in_member_variable)
- color = cache.member_variable_color;
- else if (in_function_name)
- color = cache.function_color;
- else if (is_symbol)
- color = cache.symbol_color;
- else if (is_number)
- color = cache.number_color;
-
- prev_is_char = is_char;
- prev_is_number = is_number;
- }
- int char_w;
-
- //handle tabulator
+ if (in_search_result) {
+ Color border_color = (line == search_result_line && j >= search_result_col && j < search_result_col + search_text.length()) ? cache.font_color : cache.search_result_border_color;
- 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...
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color);
- } 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 (j == search_text_col)
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color);
+ if (j == search_text_col + search_text.length() - 1)
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
+ }
- if ((char_ofs + char_margin + char_w) >= xmargin_end) {
- if (syntax_coloring)
- continue;
- else
- break;
- }
+ if (highlight_all_occurrences) {
+ if (highlighted_text_col != -1) {
- bool in_search_result = false;
+ // if we are at the end check for new word on same line
+ if (j > highlighted_text_col + highlighted_text.length()) {
+ highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j);
+ }
- if (search_text_col != -1) {
- // if we are at the end check for new search result on same line
- if (j >= search_text_col + search_text.length())
- search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j);
+ bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col + highlighted_text.length());
- in_search_result = j >= search_text_col && j < search_text_col + search_text.length();
+ // if this is the original highlighted text we don't want to highlight it again
+ if (cursor.line == line && cursor_wrap_index == line_wrap_index && (cursor.column >= highlighted_text_col && cursor.column <= highlighted_text_col + highlighted_text.length())) {
+ in_highlighted_word = false;
+ }
- if (in_search_result) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.search_result_color);
+ if (in_highlighted_word) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color);
+ }
+ }
}
- }
- //current line highlighting
- 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 (line == cursor.line && highlight_current_line) {
- // if its the last char draw to end of the line
- if (j == str.length() - 1) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
- }
- // actual text
- if (!in_selection) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
+ if (highlighted_word_col != -1) {
+ if (j + last_wrap_column > highlighted_word_col + highlighted_word.length()) {
+ highlighted_word_col = _get_column_pos_of_word(highlighted_word, fullstr, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j + last_wrap_column);
+ }
+ underlined = (j + last_wrap_column >= highlighted_word_col && j + last_wrap_column < highlighted_word_col + highlighted_word.length());
}
- }
- if (in_selection) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, 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 == last_wrap_column + j) ||
+ (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_open_matching || brace_open_mismatch))) {
+
+ if (brace_open_mismatch)
+ color = cache.brace_mismatch_color;
+ drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ }
- if (in_search_result) {
- Color border_color = (line == search_result_line && j >= search_result_col && j < search_result_col + search_text.length()) ? cache.font_color : cache.search_result_border_color;
+ if ((brace_close_match_line == line && brace_close_match_column == last_wrap_column + j) ||
+ (cursor.column == last_wrap_column + j + 1 && cursor.line == line && cursor_wrap_index == line_wrap_index && (brace_close_matching || brace_close_mismatch))) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, 1)), border_color);
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y + get_row_height() - 1), Size2i(char_w, 1)), border_color);
+ if (brace_close_mismatch)
+ color = cache.brace_mismatch_color;
+ drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ }
+ }
- if (j == search_text_col)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(1, get_row_height())), border_color);
- if (j == search_text_col + search_text.length() - 1)
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + char_w + ofs_x - 1, ofs_y), Size2i(1, get_row_height())), border_color);
- }
+ if (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index) {
- if (highlight_all_occurrences) {
- if (highlighted_text_col != -1) {
+ cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
- // if we are at the end check for new word on same line
- if (j > highlighted_text_col + highlighted_text.length()) {
- highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, j);
+ if (insert_mode) {
+ cursor_pos.y += (get_row_height() - 3);
}
- bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col + highlighted_text.length());
+ int caret_w = (str[j] == '\t') ? cache.font->get_char_size(' ').width : char_w;
+ if (ime_text.length() > 0) {
+ int ofs = 0;
+ while (true) {
+ if (ofs >= ime_text.length())
+ break;
+
+ CharType cchar = ime_text[ofs];
+ CharType next = ime_text[ofs + 1];
+ int im_char_width = cache.font->get_char_size(cchar, next).width;
+
+ if ((char_ofs + char_margin + im_char_width) >= xmargin_end)
+ break;
+
+ bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
+ if (selected) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
+ } else {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
+ }
- /* if this is the original highlighted text we don't want to highlight it again */
- if (cursor.line == line && (cursor.column >= highlighted_text_col && cursor.column <= highlighted_text_col + highlighted_text.length())) {
- in_highlighted_word = false;
- }
+ drawer.draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
- if (in_highlighted_word) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin + ofs_x, ofs_y), Size2i(char_w, get_row_height())), cache.word_highlighted_color);
+ char_ofs += im_char_width;
+ ofs++;
+ }
+ }
+ if (ime_text.length() == 0) {
+ if (draw_caret) {
+ if (insert_mode) {
+ int caret_h = (block_caret) ? 4 : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, caret_h)), cache.caret_color);
+ } else {
+ caret_w = (block_caret) ? caret_w : 1;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_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 (cursor.column == last_wrap_column + j && cursor.line == line && cursor_wrap_index == line_wrap_index && block_caret && draw_caret && !insert_mode) {
+ color = cache.caret_background_color;
+ } else if (!syntax_coloring && block_caret) {
+ color = cache.font_color;
+ color.a *= readonly_alpha;
+ }
- if (brace_open_mismatch)
- color = cache.brace_mismatch_color;
- cache.font->draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ if (str[j] >= 32) {
+ int w = drawer.draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ if (underlined) {
+ draw_rect(Rect2(char_ofs + char_margin + ofs_x, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? 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_x, ofs_y + yofs), in_selection && override_selected_font_color ? 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))) {
+ char_ofs += char_w;
- if (brace_close_mismatch)
- color = cache.brace_mismatch_color;
- cache.font->draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
+ if (line_wrap_index == line_wrap_amount && j == str.length() - 1 && is_folded(line)) {
+ int yofs = (get_row_height() - cache.folded_eol_icon->get_height()) / 2;
+ int xofs = cache.folded_eol_icon->get_width() / 2;
+ Color eol_color = cache.code_folding_color;
+ eol_color.a = 1;
+ cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs + ofs_x, ofs_y + yofs), eol_color);
}
}
- if (cursor.column == j && cursor.line == line) {
+ if (cursor.column == last_wrap_column + str.length() && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) {
cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
if (insert_mode) {
cursor_pos.y += (get_row_height() - 3);
}
-
- int caret_w = (str[j] == '\t') ? cache.font->get_char_size(' ').width : char_w;
if (ime_text.length() > 0) {
int ofs = 0;
while (true) {
@@ -1226,7 +1208,7 @@ void TextEdit::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
}
- cache.font->draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
+ drawer.draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
char_ofs += im_char_width;
ofs++;
@@ -1235,92 +1217,17 @@ void TextEdit::_notification(int p_what) {
if (ime_text.length() == 0) {
if (draw_caret) {
if (insert_mode) {
+ int char_w = cache.font->get_char_size(' ').width;
int caret_h = (block_caret) ? 4 : 1;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, caret_h)), cache.caret_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(char_w, caret_h)), cache.caret_color);
} else {
- caret_w = (block_caret) ? caret_w : 1;
+ int char_w = cache.font->get_char_size(' ').width;
+ int caret_w = (block_caret) ? char_w : 1;
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
}
}
}
}
-
- if (cursor.column == j && cursor.line == line && block_caret && draw_caret && !insert_mode) {
- color = cache.caret_background_color;
- } else if (!syntax_coloring && block_caret) {
- color = cache.font_color;
- color.a *= readonly_alpha;
- }
-
- if (str[j] >= 32) {
- int w = cache.font->draw_char(ci, Point2i(char_ofs + char_margin + ofs_x, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
- if (underlined) {
- draw_rect(Rect2(char_ofs + char_margin + ofs_x, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? 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_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color);
- }
-
- char_ofs += char_w;
-
- if (j == str.length() - 1 && is_folded(line)) {
- int yofs = (get_row_height() - cache.folded_eol_icon->get_height()) / 2;
- int xofs = cache.folded_eol_icon->get_width() / 2;
- Color eol_color = cache.code_folding_color;
- eol_color.a = 1;
- cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs + ofs_x, ofs_y + yofs), eol_color);
- }
- }
-
- if (cursor.column == str.length() && cursor.line == line && (char_ofs + char_margin) >= xmargin_beg) {
-
- cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y);
-
- if (insert_mode) {
- cursor_pos.y += (get_row_height() - 3);
- }
- if (ime_text.length() > 0) {
- int ofs = 0;
- while (true) {
- if (ofs >= ime_text.length())
- break;
-
- CharType cchar = ime_text[ofs];
- CharType next = ime_text[ofs + 1];
- int im_char_width = cache.font->get_char_size(cchar, next).width;
-
- if ((char_ofs + char_margin + im_char_width) >= xmargin_end)
- break;
-
- bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y;
- if (selected) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 3)), color);
- } else {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(char_ofs + char_margin, ofs_y + get_row_height()), Size2(im_char_width, 1)), color);
- }
-
- cache.font->draw_char(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + ascent), cchar, next, color);
-
- char_ofs += im_char_width;
- ofs++;
- }
- }
- if (ime_text.length() == 0) {
- if (draw_caret) {
- if (insert_mode) {
- int char_w = cache.font->get_char_size(' ').width;
- int caret_h = (block_caret) ? 4 : 1;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(char_w, caret_h)), cache.caret_color);
- } else {
- int char_w = cache.font->get_char_size(' ').width;
- int caret_w = (block_caret) ? char_w : 1;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(cursor_pos, Size2i(caret_w, get_row_height())), cache.caret_color);
- }
- }
- }
}
}
@@ -1484,6 +1391,7 @@ void TextEdit::_notification(int p_what) {
OS::get_singleton()->set_ime_position(get_global_position() + cursor_pos + Point2(0, get_row_height()));
OS::get_singleton()->set_ime_intermediate_text_callback(_ime_text_callback, this);
}
+
} break;
case NOTIFICATION_FOCUS_ENTER: {
@@ -1498,9 +1406,8 @@ void TextEdit::_notification(int p_what) {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->show_virtual_keyboard(get_text(), get_global_rect());
if (raised_from_completion) {
- VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 1);
+ VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1);
}
-
} break;
case NOTIFICATION_FOCUS_EXIT: {
@@ -1512,7 +1419,7 @@ void TextEdit::_notification(int p_what) {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->hide_virtual_keyboard();
if (raised_from_completion) {
- VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 0);
+ VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0);
}
} break;
}
@@ -1664,17 +1571,22 @@ void TextEdit::backspace_at_cursor() {
cursor_set_column(prev_column);
}
-void TextEdit::indent_selection_right() {
+void TextEdit::indent_right() {
- if (!is_selection_active()) {
- return;
- }
+ int start_line;
+ int end_line;
begin_complex_operation();
- int start_line = get_selection_from_line();
- int end_line = get_selection_to_line();
+
+ if (is_selection_active()) {
+ start_line = get_selection_from_line();
+ end_line = get_selection_to_line();
+ } else {
+ start_line = cursor.line;
+ end_line = start_line;
+ }
// ignore if the cursor is not past the first column
- if (get_selection_to_column() == 0) {
+ if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
@@ -1688,23 +1600,31 @@ void TextEdit::indent_selection_right() {
set_line(i, line_text);
}
- // fix selection being off by one on the last line
- selection.to_column++;
+ // fix selection and cursor being off by one on the last line
+ if (is_selection_active()) {
+ select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1);
+ }
+ cursor_set_column(cursor.column + 1, false);
end_complex_operation();
update();
}
-void TextEdit::indent_selection_left() {
+void TextEdit::indent_left() {
- if (!is_selection_active()) {
- return;
- }
+ int start_line;
+ int end_line;
begin_complex_operation();
- int start_line = get_selection_from_line();
- int end_line = get_selection_to_line();
+
+ if (is_selection_active()) {
+ start_line = get_selection_from_line();
+ end_line = get_selection_to_line();
+ } else {
+ start_line = cursor.line;
+ end_line = start_line;
+ }
// ignore if the cursor is not past the first column
- if (get_selection_to_column() == 0) {
+ if (is_selection_active() && get_selection_to_column() == 0) {
end_line--;
}
String last_line_text = get_line(end_line);
@@ -1721,10 +1641,11 @@ void TextEdit::indent_selection_left() {
}
}
- // fix selection being off by one on the last line
- if (last_line_text != get_line(end_line) && selection.to_column > 0) {
- selection.to_column--;
+ // fix selection and cursor being off by one on the last line
+ if (is_selection_active() && last_line_text != get_line(end_line)) {
+ select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1);
}
+ cursor_set_column(cursor.column - 1, false);
end_complex_operation();
update();
}
@@ -1734,14 +1655,16 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
float rows = p_mouse.y;
rows -= cache.style_normal->get_margin(MARGIN_TOP);
rows /= get_row_height();
- int lsp = get_line_scroll_pos(true);
- int row = cursor.line_ofs + (rows + (round(v_scroll->get_value()) - lsp));
+ rows += get_v_scroll_offset();
+ int first_vis_line = get_first_visible_line();
+ int row = first_vis_line + Math::floor(rows);
+ int wrap_index = 0;
+
+ if (is_wrap_enabled() || is_hiding_enabled()) {
- if (is_hiding_enabled()) {
- // row will be offset by the hidden rows
- int f_ofs = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(rows + 1, text.size() - cursor.line_ofs)) - 1;
- row = cursor.line_ofs + (f_ofs + (round(v_scroll->get_value()) - lsp));
- row = CLAMP(row, 0, text.size() - num_lines_from(text.size() - 1, -1));
+ int f_ofs = num_lines_from_rows(first_vis_line, cursor.wrap_ofs, rows + 1, wrap_index) - 1;
+ row = first_vis_line + f_ofs;
+ row = CLAMP(row, 0, get_last_visible_line() + 1);
}
if (row < 0)
@@ -1755,9 +1678,19 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
col = text[row].size();
} else {
- col = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width);
- col += cursor.x_ofs;
- col = get_char_pos_for(col, get_line(row));
+ int colx = p_mouse.x - (cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width);
+ colx += cursor.x_ofs;
+ col = get_char_pos_for_line(colx, row, wrap_index);
+ if (is_wrap_enabled() && wrap_index < times_line_wraps(row)) {
+ // move back one if we are at the end of the row
+ Vector<String> rows = get_wrap_rows_text(row);
+ int row_end_col = 0;
+ for (int i = 0; i < wrap_index + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (col >= row_end_col)
+ col -= 1;
+ }
}
r_row = row;
@@ -1808,10 +1741,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->is_pressed()) {
if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
- _scroll_up(3 * mb->get_factor());
+ if (mb->get_shift()) {
+ h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
+ } else {
+ _scroll_up(3 * mb->get_factor());
+ }
}
if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
- _scroll_down(3 * mb->get_factor());
+ if (mb->get_shift()) {
+ h_scroll->set_value(h_scroll->get_value() + (100 * mb->get_factor()));
+ } else {
+ _scroll_down(3 * mb->get_factor());
+ }
}
if (mb->get_button_index() == BUTTON_WHEEL_LEFT) {
h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
@@ -1824,7 +1765,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_reset_caret_blink_timer();
int row, col;
- update_line_scroll_pos();
_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
if (mb->get_command() && highlighted_word != String()) {
@@ -1942,7 +1882,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} else if (mb->is_doubleclick() && text[cursor.line].length()) {
- //doubleclick select world
+ //doubleclick select word
selection.selecting_mode = Selection::MODE_WORD;
_update_selection_mode_word();
last_dblclk = OS::get_singleton()->get_ticks_msec();
@@ -1953,6 +1893,30 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ _reset_caret_blink_timer();
+
+ int row, col;
+ _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
+
+ if (is_right_click_moving_caret()) {
+ if (is_selection_active()) {
+
+ int from_line = get_selection_from_line();
+ int to_line = get_selection_to_line();
+ int from_column = get_selection_from_column();
+ int to_column = get_selection_to_column();
+
+ if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) {
+ // Right click is outside the seleted text
+ deselect();
+ }
+ }
+ if (!is_selection_active()) {
+ cursor_set_line(row, true, false);
+ cursor_set_column(col);
+ }
+ }
+
menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
menu->popup();
@@ -2065,9 +2029,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (completion_index > 0) {
completion_index--;
- completion_current = completion_options[completion_index];
- update();
+ } else {
+ completion_index = completion_options.size() - 1;
}
+ completion_current = completion_options[completion_index];
+ update();
+
accept_event();
return;
}
@@ -2076,9 +2043,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (completion_index < completion_options.size() - 1) {
completion_index++;
- completion_current = completion_options[completion_index];
- update();
+ } else {
+ completion_index = 0;
}
+ completion_current = completion_options[completion_index];
+ update();
+
accept_event();
return;
}
@@ -2216,9 +2186,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
case KEY_TAB: {
if (k->get_shift()) {
- indent_selection_left();
+ indent_left();
} else {
- indent_selection_right();
+ indent_right();
}
dobreak = true;
accept_event();
@@ -2389,33 +2359,55 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (readonly)
break;
- if (selection.active) {
-
+ if (is_selection_active()) {
+ if (k->get_shift()) {
+ indent_left();
+ } else {
+ indent_right();
+ }
} else {
if (k->get_shift()) {
//simple unindent
int cc = cursor.column;
+
+ const int len = text[cursor.line].length();
+ const String &line = text[cursor.line];
+
+ int left = 0; // number of whitespace chars at beginning of line
+ while (left < len && (line[left] == '\t' || line[left] == ' '))
+ left++;
+ cc = MIN(cc, left);
+
+ while (cc < indent_size && cc < left && line[cc] == ' ')
+ cc++;
+
if (cc > 0 && cc <= text[cursor.line].length()) {
- if (text[cursor.line][cursor.column - 1] == '\t') {
- backspace_at_cursor();
+ if (text[cursor.line][cc - 1] == '\t') {
+ _remove_text(cursor.line, cc - 1, cursor.line, cc);
+ if (cursor.column >= left)
+ cursor_set_column(MAX(0, cursor.column - 1));
+ update();
} else {
- if (cursor.column - indent_size >= 0) {
+ int n = 0;
- bool unindent = true;
- for (int i = 1; i <= indent_size; i++) {
- if (text[cursor.line][cursor.column - i] != ' ') {
- unindent = false;
- break;
- }
+ for (int i = 1; i <= MIN(cc, indent_size); i++) {
+ if (line[cc - i] != ' ') {
+ break;
}
+ n++;
+ }
- if (unindent) {
- _remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column);
- cursor_set_column(cursor.column - indent_size);
- }
+ if (n > 0) {
+ _remove_text(cursor.line, cc - n, cursor.line, cc);
+ if (cursor.column > left - n) // inside text?
+ cursor_set_column(MAX(0, cursor.column - n));
+ update();
}
}
+ } else if (cc == 0 && line.length() > 0 && line[0] == '\t') {
+ _remove_text(cursor.line, 0, cursor.line, 1);
+ update();
}
} else {
//simple indent
@@ -2478,6 +2470,12 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
cursor_set_line(line);
cursor_set_column(column);
+#ifdef APPLE_STYLE_KEYS
+ } else if (k->get_command()) {
+ int cursor_current_column = cursor.column;
+ cursor.column = 0;
+ _remove_text(cursor.line, 0, cursor.line, cursor_current_column);
+#endif
} else {
if (cursor.line > 0 && is_line_hidden(cursor.line - 1))
unfold_line(cursor.line - 1);
@@ -2514,28 +2512,26 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
} else if (k->get_command()) {
#endif
- bool prev_char = false;
int cc = cursor.column;
if (cc == 0 && cursor.line > 0) {
cursor_set_line(cursor.line - 1);
cursor_set_column(text[cursor.line].length());
- break;
- }
-
- while (cc > 0) {
+ } else {
+ bool prev_char = false;
- bool ischar = _is_text_char(text[cursor.line][cc - 1]);
+ while (cc > 0) {
+ bool ischar = _is_text_char(text[cursor.line][cc - 1]);
- if (prev_char && !ischar)
- break;
+ if (prev_char && !ischar)
+ break;
- prev_char = ischar;
- cc--;
+ prev_char = ischar;
+ cc--;
+ }
+ cursor_set_column(cc);
}
- cursor_set_column(cc);
-
} else if (cursor.column == 0) {
if (cursor.line > 0) {
@@ -2578,27 +2574,25 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
} else if (k->get_command()) {
#endif
- bool prev_char = false;
int cc = cursor.column;
if (cc == text[cursor.line].length() && cursor.line < text.size() - 1) {
cursor_set_line(cursor.line + 1);
cursor_set_column(0);
- break;
- }
-
- while (cc < text[cursor.line].length()) {
+ } else {
+ bool prev_char = false;
- bool ischar = _is_text_char(text[cursor.line][cc]);
+ while (cc < text[cursor.line].length()) {
+ bool ischar = _is_text_char(text[cursor.line][cc]);
- if (prev_char && !ischar)
- break;
- prev_char = ischar;
- cc++;
+ if (prev_char && !ischar)
+ break;
+ prev_char = ischar;
+ cc++;
+ }
+ cursor_set_column(cc);
}
- cursor_set_column(cc);
-
} else if (cursor.column == text[cursor.line].length()) {
if (cursor.line < text.size() - 1) {
@@ -2639,11 +2633,25 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
- if (k->get_command())
+ if (k->get_command()) {
cursor_set_line(0);
- else
+ } else
#endif
- cursor_set_line(cursor_get_line() - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1));
+ {
+ int cur_wrap_index = get_cursor_wrap_index();
+ if (cur_wrap_index > 0) {
+ cursor_set_line(cursor.line, true, false, cur_wrap_index - 1);
+ } else if (cursor.line == 0) {
+ cursor_set_column(0);
+ } else {
+ int new_line = cursor.line - num_lines_from(cursor.line - 1, -1);
+ if (line_wraps(new_line)) {
+ cursor_set_line(new_line, true, false, times_line_wraps(new_line));
+ } else {
+ cursor_set_line(new_line, true, false);
+ }
+ }
+ }
if (k->get_shift())
_post_shift_selection();
@@ -2670,24 +2678,34 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_scroll_lines_down();
break;
}
+
#else
if (k->get_command() && k->get_alt()) {
_scroll_lines_down();
break;
}
- if (k->get_command())
- cursor_set_line(text.size() - 1, true, false);
- else
+ if (k->get_command()) {
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
+ } else
#endif
- cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false);
+ {
+ int cur_wrap_index = get_cursor_wrap_index();
+ if (cur_wrap_index < times_line_wraps(cursor.line)) {
+ cursor_set_line(cursor.line, true, false, cur_wrap_index + 1);
+ } else if (cursor.line == get_last_unhidden_line()) {
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ int new_line = cursor.line + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1);
+ cursor_set_line(new_line, true, false, 0);
+ }
+ }
if (k->get_shift())
_post_shift_selection();
_cancel_code_hint();
} break;
-
case KEY_DELETE: {
if (readonly)
@@ -2750,7 +2768,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
next_line = line;
next_column = column;
-
+#ifdef APPLE_STYLE_KEYS
+ } else if (k->get_command()) {
+ next_column = curline_len;
+ next_line = cursor.line;
+#endif
} else {
next_column = cursor.column < curline_len ? (cursor.column + 1) : 0;
}
@@ -2790,19 +2812,31 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
cursor_set_line(0);
cursor_set_column(0);
} else {
- // compute whitespace symbols seq length
- int current_line_whitespace_len = 0;
- while (current_line_whitespace_len < text[cursor.line].length()) {
- CharType c = text[cursor.line][current_line_whitespace_len];
- if (c != '\t' && c != ' ')
- break;
- current_line_whitespace_len++;
+
+ // move cursor column to start of wrapped row and then to start of text
+ Vector<String> rows = get_wrap_rows_text(cursor.line);
+ int wi = get_cursor_wrap_index();
+ int row_start_col = 0;
+ for (int i = 0; i < wi; i++) {
+ row_start_col += rows[i].length();
}
+ if (cursor.column == row_start_col || wi == 0) {
+ // compute whitespace symbols seq length
+ int current_line_whitespace_len = 0;
+ while (current_line_whitespace_len < text[cursor.line].length()) {
+ CharType c = text[cursor.line][current_line_whitespace_len];
+ if (c != '\t' && c != ' ')
+ break;
+ current_line_whitespace_len++;
+ }
- if (cursor_get_column() == current_line_whitespace_len)
- cursor_set_column(0);
- else
- cursor_set_column(current_line_whitespace_len);
+ if (cursor_get_column() == current_line_whitespace_len)
+ cursor_set_column(0);
+ else
+ cursor_set_column(current_line_whitespace_len);
+ } else {
+ cursor_set_column(row_start_col);
+ }
}
if (k->get_shift())
@@ -2827,7 +2861,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_shift())
_pre_shift_selection();
- cursor_set_line(text.size() - 1, true, false);
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
if (k->get_shift())
_post_shift_selection();
@@ -2842,8 +2876,20 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
_pre_shift_selection();
if (k->get_command())
- cursor_set_line(text.size() - 1, true, false);
- cursor_set_column(text[cursor.line].length());
+ cursor_set_line(get_last_unhidden_line(), true, false, 9999);
+
+ // move cursor column to end of wrapped row and then to end of text
+ Vector<String> rows = get_wrap_rows_text(cursor.line);
+ int wi = get_cursor_wrap_index();
+ int row_end_col = -1;
+ for (int i = 0; i < wi + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (wi == rows.size() - 1 || cursor.column == row_end_col) {
+ cursor_set_column(text[cursor.line].length());
+ } else {
+ cursor_set_column(row_end_col);
+ }
if (k->get_shift())
_post_shift_selection();
@@ -2867,7 +2913,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->get_shift())
_pre_shift_selection();
- cursor_set_line(cursor_get_line() - num_lines_from(cursor.line, -get_visible_rows()), true, false);
+ int wi;
+ int n_line = cursor.line - num_lines_from_rows(cursor.line, get_cursor_wrap_index(), -get_visible_rows(), wi) + 1;
+ cursor_set_line(n_line, true, false, wi);
if (k->get_shift())
_post_shift_selection();
@@ -2881,14 +2929,16 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
scancode_handled = false;
break;
}
- // numlock disabled. fallthrough to key_pageup
+ // numlock disabled. fallthrough to key_pagedown
}
case KEY_PAGEDOWN: {
if (k->get_shift())
_pre_shift_selection();
- cursor_set_line(cursor_get_line() + num_lines_from(cursor.line, get_visible_rows()), true, false);
+ int wi;
+ int n_line = cursor.line + num_lines_from_rows(cursor.line, get_cursor_wrap_index(), get_visible_rows(), wi) - 1;
+ cursor_set_line(n_line, true, false, wi);
if (k->get_shift())
_post_shift_selection();
@@ -2899,13 +2949,64 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
} break;
case KEY_A: {
- if (!k->get_command() || k->get_shift() || k->get_alt()) {
+#ifndef APPLE_STYLE_KEYS
+ if (!k->get_control() || k->get_shift() || k->get_alt()) {
scancode_handled = false;
break;
}
-
select_all();
+#else
+ if ((!k->get_command() && !k->get_control())) {
+ scancode_handled = false;
+ break;
+ }
+ if (!k->get_shift() && k->get_command())
+ select_all();
+ else if (k->get_control()) {
+ if (k->get_shift())
+ _pre_shift_selection();
+
+ int current_line_whitespace_len = 0;
+ while (current_line_whitespace_len < text[cursor.line].length()) {
+ CharType c = text[cursor.line][current_line_whitespace_len];
+ if (c != '\t' && c != ' ')
+ break;
+ current_line_whitespace_len++;
+ }
+
+ if (cursor_get_column() == current_line_whitespace_len)
+ cursor_set_column(0);
+ else
+ cursor_set_column(current_line_whitespace_len);
+
+ if (k->get_shift())
+ _post_shift_selection();
+ else if (k->get_command() || k->get_control())
+ deselect();
+ }
+ } break;
+ case KEY_E: {
+
+ if (!k->get_control() || k->get_command() || k->get_alt()) {
+ scancode_handled = false;
+ break;
+ }
+
+ if (k->get_shift())
+ _pre_shift_selection();
+ if (k->get_command())
+ cursor_set_line(text.size() - 1, true, false);
+ cursor_set_column(text[cursor.line].length());
+
+ if (k->get_shift())
+ _post_shift_selection();
+ else if (k->get_command() || k->get_control())
+ deselect();
+
+ _cancel_completion();
+ completion_hint = "";
+#endif
} break;
case KEY_X: {
if (readonly) {
@@ -3030,7 +3131,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- if (!scancode_handled && !k->get_command()) { //for german kbds
+ if (!scancode_handled && !k->get_command()) { //for German kbds
if (k->get_unicode() >= 32) {
@@ -3076,45 +3177,55 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
void TextEdit::_scroll_up(real_t p_delta) {
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta))
+ scrolling = false;
+
if (scrolling) {
target_v_scroll = (target_v_scroll - p_delta);
} else {
- target_v_scroll = (v_scroll->get_value() - p_delta);
+ target_v_scroll = (get_v_scroll() - p_delta);
}
if (smooth_scroll_enabled) {
if (target_v_scroll <= 0) {
target_v_scroll = 0;
}
- scrolling = true;
- set_physics_process(true);
+ if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
+ v_scroll->set_value(target_v_scroll);
+ } else {
+ scrolling = true;
+ set_physics_process_internal(true);
+ }
} else {
- v_scroll->set_value(target_v_scroll);
+ set_v_scroll(target_v_scroll);
}
}
void TextEdit::_scroll_down(real_t p_delta) {
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta))
+ scrolling = false;
+
if (scrolling) {
target_v_scroll = (target_v_scroll + p_delta);
} else {
- target_v_scroll = (v_scroll->get_value() + p_delta);
+ target_v_scroll = (get_v_scroll() + p_delta);
}
if (smooth_scroll_enabled) {
- int max_v_scroll = get_total_unhidden_rows();
- if (!scroll_past_end_of_file_enabled) {
- max_v_scroll -= get_visible_rows();
- max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows());
- }
-
+ int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
if (target_v_scroll > max_v_scroll) {
target_v_scroll = max_v_scroll;
+ v_scroll->set_value(target_v_scroll);
+ }
+ if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
+ v_scroll->set_value(target_v_scroll);
+ } else {
+ scrolling = true;
+ set_physics_process_internal(true);
}
- scrolling = true;
- set_physics_process(true);
} else {
- v_scroll->set_value(target_v_scroll);
+ set_v_scroll(target_v_scroll);
}
}
@@ -3145,35 +3256,37 @@ void TextEdit::_scroll_lines_up() {
scrolling = false;
// adjust the vertical scroll
- if (get_v_scroll() >= 0) {
- set_v_scroll(get_v_scroll() - 1);
- }
+ set_v_scroll(get_v_scroll() - 1);
+
+ // adjust the cursor to viewport
+ if (!selection.active) {
+ int cur_line = cursor.line;
+ int cur_wrap = get_cursor_wrap_index();
+ int last_vis_line = get_last_visible_line();
+ int last_vis_wrap = get_last_visible_line_wrap_index();
- // adjust the cursor
- int num_lines = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), get_visible_rows());
- if (cursor.line >= cursor.line_ofs + num_lines && !selection.active) {
- cursor_set_line(cursor.line_ofs + num_lines, false, false);
+ if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
+ cursor_set_line(last_vis_line, false, false, last_vis_wrap);
+ }
}
}
void TextEdit::_scroll_lines_down() {
scrolling = false;
- // calculate the maximum vertical scroll position
- int max_v_scroll = get_total_unhidden_rows();
- if (!scroll_past_end_of_file_enabled) {
- max_v_scroll -= get_visible_rows();
- max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows());
- }
-
// adjust the vertical scroll
- if (get_v_scroll() < max_v_scroll) {
- set_v_scroll(get_v_scroll() + 1);
- }
+ set_v_scroll(get_v_scroll() + 1);
+
+ // adjust the cursor to viewport
+ if (!selection.active) {
+ int cur_line = cursor.line;
+ int cur_wrap = get_cursor_wrap_index();
+ int first_vis_line = get_first_visible_line();
+ int first_vis_wrap = cursor.wrap_ofs;
- // adjust the cursor
- if (cursor.line <= cursor.line_ofs - 1 && !selection.active) {
- cursor_set_line(cursor.line_ofs, false, false);
+ if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
+ cursor_set_line(first_vis_line, false, false, first_vis_wrap);
+ }
}
}
@@ -3227,6 +3340,8 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
text.set_hidden(p_line, false);
}
+ text.set_line_wrap_amount(p_line, -1);
+
r_end_line = p_line + substrings.size() - 1;
r_end_column = text[r_end_line].length() - postinsert_text.length();
@@ -3235,6 +3350,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
text_changed_dirty = true;
}
+ _line_edited_from(p_line);
}
String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) const {
@@ -3280,11 +3396,14 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
text.set(p_from_line, pre_text + post_text);
+ text.set_line_wrap_amount(p_from_line, -1);
+
if (!text_changed_dirty && !setting_text) {
if (is_inside_tree())
MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
text_changed_dirty = true;
}
+ _line_edited_from(p_from_line);
}
void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r_end_line, int *r_end_char) {
@@ -3407,6 +3526,13 @@ void TextEdit::_insert_text_at_cursor(const String &p_text) {
update();
}
+void TextEdit::_line_edited_from(int p_line) {
+ int cache_size = color_region_cache.size();
+ for (int i = p_line; i < cache_size; i++) {
+ color_region_cache.erase(i);
+ }
+}
+
int TextEdit::get_char_count() {
int totalsize = 0;
@@ -3430,61 +3556,63 @@ int TextEdit::get_visible_rows() const {
int total = cache.size.height;
total -= cache.style_normal->get_minimum_size().height;
+ if (h_scroll->is_visible_in_tree())
+ total -= h_scroll->get_size().height;
total /= get_row_height();
return total;
}
-int TextEdit::get_total_unhidden_rows() const {
- if (!is_hiding_enabled())
+int TextEdit::get_total_visible_rows() const {
+
+ // returns the total amount of rows we need in the editor.
+ // This skips hidden lines and counts each wrapping of a line.
+ if (!is_hiding_enabled() && !is_wrap_enabled())
return text.size();
- int total_unhidden = 0;
+ int total_rows = 0;
for (int i = 0; i < text.size(); i++) {
- if (!text.is_hidden(i))
- total_unhidden++;
+ if (!text.is_hidden(i)) {
+ total_rows++;
+ total_rows += times_line_wraps(i);
+ }
}
- return total_unhidden;
+ return total_rows;
}
-double TextEdit::get_line_scroll_pos(bool p_recalculate) const {
+void TextEdit::update_wrap_at() {
- if (!is_hiding_enabled())
- return cursor.line_ofs;
- if (!p_recalculate)
- return line_scroll_pos;
+ wrap_at = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width - wrap_right_offset;
+ update_cursor_wrap_offset();
+ text.clear_wrap_cache();
- // count num unhidden lines to the cursor line ofs
- double new_line_scroll_pos = 0;
- int to = CLAMP(cursor.line_ofs, 0, text.size() - 1);
- for (int i = 0; i < to; i++) {
- if (!text.is_hidden(i))
- new_line_scroll_pos++;
+ for (int i = 0; i < text.size(); i++) {
+ // update all values that wrap
+ if (!line_wraps(i))
+ continue;
+ Vector<String> rows = get_wrap_rows_text(i);
+ text.set_line_wrap_amount(i, rows.size() - 1);
}
- return new_line_scroll_pos;
}
-void TextEdit::update_line_scroll_pos() {
+void TextEdit::adjust_viewport_to_cursor() {
- if (!is_hiding_enabled()) {
- line_scroll_pos = cursor.line_ofs;
- return;
- }
+ // make sure cursor is visible on the screen
+ scrolling = false;
- // count num unhidden lines to the cursor line ofs
- double new_line_scroll_pos = 0;
- int to = CLAMP(cursor.line_ofs, 0, text.size() - 1);
- for (int i = 0; i < to; i++) {
- if (!text.is_hidden(i))
- new_line_scroll_pos++;
- }
- line_scroll_pos = new_line_scroll_pos;
-}
+ int cur_line = cursor.line;
+ int cur_wrap = get_cursor_wrap_index();
-void TextEdit::adjust_viewport_to_cursor() {
- scrolling = false;
+ int first_vis_line = get_first_visible_line();
+ int first_vis_wrap = cursor.wrap_ofs;
+ int last_vis_line = get_last_visible_line();
+ int last_vis_wrap = get_last_visible_line_wrap_index();
- if (cursor.line_ofs > cursor.line) {
- cursor.line_ofs = cursor.line;
+ if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
+ // cursor is above screen
+ set_line_as_first_visible(cur_line, cur_wrap);
+ } else if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
+ // cursor is below screen
+ set_line_as_last_visible(cur_line, cur_wrap);
}
int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width;
@@ -3492,90 +3620,174 @@ void TextEdit::adjust_viewport_to_cursor() {
visible_width -= v_scroll->get_combined_minimum_size().width;
visible_width -= 20; // give it a little more space
- int visible_rows = get_visible_rows();
- if (h_scroll->is_visible_in_tree() && !scroll_past_end_of_file_enabled)
- visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height());
- int num_rows = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs));
-
- // make sure the cursor is on the screen
- // above the caret
- if (cursor.line > (cursor.line_ofs + MAX(num_rows, visible_rows))) {
- cursor.line_ofs = cursor.line - num_lines_from(cursor.line, -visible_rows) + 1;
- }
- // below the caret
- if (cursor.line_ofs == cursor.line) {
- cursor.line_ofs = cursor.line - 2;
- }
- int line_ofs_max = text.size() - 1;
- if (!scroll_past_end_of_file_enabled) {
- line_ofs_max -= num_lines_from(text.size() - 1, -visible_rows) - 1;
- line_ofs_max += (h_scroll->is_visible_in_tree() ? 1 : 0);
- line_ofs_max += (cursor.line == text.size() - 1 ? 1 : 0);
- }
- line_ofs_max = MAX(line_ofs_max, 0);
- cursor.line_ofs = CLAMP(cursor.line_ofs, 0, line_ofs_max);
-
- // adjust x offset
- 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 (!is_wrap_enabled()) {
+ // adjust x offset
+ int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
- if (cursor_x < cursor.x_ofs)
- cursor.x_ofs = cursor_x;
+ if (cursor_x > (cursor.x_ofs + visible_width))
+ cursor.x_ofs = cursor_x - visible_width + 1;
- updating_scrolls = true;
- h_scroll->set_value(cursor.x_ofs);
- update_line_scroll_pos();
- double new_v_scroll = get_line_scroll_pos();
- // keep offset if smooth scroll is enabled
- if (smooth_scroll_enabled) {
- new_v_scroll += fmod(v_scroll->get_value(), 1.0);
+ if (cursor_x < cursor.x_ofs)
+ cursor.x_ofs = cursor_x;
+ } else {
+ cursor.x_ofs = 0;
}
- v_scroll->set_value(new_v_scroll);
- updating_scrolls = false;
+ h_scroll->set_value(cursor.x_ofs);
+
update();
}
void TextEdit::center_viewport_to_cursor() {
- scrolling = false;
- if (cursor.line_ofs > cursor.line)
- cursor.line_ofs = cursor.line;
+ // move viewport so the cursor is in the center of the screen
+ scrolling = false;
if (is_line_hidden(cursor.line))
unfold_line(cursor.line);
+ set_line_as_center_visible(cursor.line, get_cursor_wrap_index());
int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width;
if (v_scroll->is_visible_in_tree())
visible_width -= v_scroll->get_combined_minimum_size().width;
visible_width -= 20; // give it a little more space
- int visible_rows = get_visible_rows();
- if (h_scroll->is_visible_in_tree())
- visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height());
+ if (is_wrap_enabled()) {
+ // center x offset
+ int cursor_x = get_column_x_offset_for_line(cursor.column, cursor.line);
+
+ if (cursor_x > (cursor.x_ofs + visible_width))
+ cursor.x_ofs = cursor_x - visible_width + 1;
- int max_ofs = text.size() - (scroll_past_end_of_file_enabled ? 1 : num_lines_from(text.size() - 1, -visible_rows));
- cursor.line_ofs = CLAMP(cursor.line - num_lines_from(cursor.line - visible_rows / 2, -visible_rows / 2), 0, max_ofs);
- int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
+ if (cursor_x < cursor.x_ofs)
+ cursor.x_ofs = cursor_x;
+ } else {
+ cursor.x_ofs = 0;
+ }
+ h_scroll->set_value(cursor.x_ofs);
- if (cursor_x > (cursor.x_ofs + visible_width))
- cursor.x_ofs = cursor_x - visible_width + 1;
+ update();
+}
- if (cursor_x < cursor.x_ofs)
- cursor.x_ofs = cursor_x;
+void TextEdit::update_cursor_wrap_offset() {
+ int first_vis_line = get_first_visible_line();
+ if (line_wraps(first_vis_line)) {
+ cursor.wrap_ofs = MIN(cursor.wrap_ofs, times_line_wraps(first_vis_line));
+ } else {
+ cursor.wrap_ofs = 0;
+ }
+ set_line_as_first_visible(cursor.line_ofs, cursor.wrap_ofs);
+}
- updating_scrolls = true;
- h_scroll->set_value(cursor.x_ofs);
- update_line_scroll_pos();
- double new_v_scroll = get_line_scroll_pos();
- // keep offset if smooth scroll is enabled
- if (smooth_scroll_enabled) {
- new_v_scroll += fmod(v_scroll->get_value(), 1.0);
+bool TextEdit::line_wraps(int line) const {
+
+ ERR_FAIL_INDEX_V(line, text.size(), 0);
+ if (!is_wrap_enabled())
+ return false;
+ return text.get_line_width(line) > wrap_at;
+}
+
+int TextEdit::times_line_wraps(int line) const {
+
+ ERR_FAIL_INDEX_V(line, text.size(), 0);
+ if (!line_wraps(line))
+ return 0;
+
+ int wrap_amount = text.get_line_wrap_amount(line);
+ if (wrap_amount == -1) {
+ // update the value
+ Vector<String> rows = get_wrap_rows_text(line);
+ wrap_amount = rows.size() - 1;
+ text.set_line_wrap_amount(line, wrap_amount);
}
- v_scroll->set_value(new_v_scroll);
- updating_scrolls = false;
- update();
+
+ return wrap_amount;
+}
+
+Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
+
+ ERR_FAIL_INDEX_V(p_line, text.size(), Vector<String>());
+
+ Vector<String> lines;
+ if (!line_wraps(p_line)) {
+ lines.push_back(text[p_line]);
+ return lines;
+ }
+
+ int px = 0;
+ int col = 0;
+ String line_text = text[p_line];
+ String wrap_substring = "";
+
+ int word_px = 0;
+ String word_str = "";
+ int cur_wrap_index = 0;
+
+ int tab_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width;
+
+ while (col < line_text.length()) {
+ char c = line_text[col];
+ int w = text.get_char_width(c, line_text[col + 1], px + word_px);
+
+ int indent_ofs = (cur_wrap_index != 0 ? tab_offset_px : 0);
+
+ word_str += c;
+ word_px += w;
+ if (c == ' ') {
+ // end of a word; add this word to the substring
+ wrap_substring += word_str;
+ px += word_px;
+ word_str = "";
+ word_px = 0;
+ }
+
+ if ((indent_ofs + px + word_px) > wrap_at) {
+ // do not want to add this word
+ if (indent_ofs + word_px > wrap_at) {
+ // not enough space; add it anyway
+ wrap_substring += word_str;
+ px += word_px;
+ word_str = "";
+ word_px = 0;
+ }
+ lines.push_back(wrap_substring);
+ // reset for next wrap
+ cur_wrap_index++;
+ wrap_substring = "";
+ px = 0;
+ }
+ col++;
+ }
+ // line ends before hit wrap_at; add this word to the substring
+ wrap_substring += word_str;
+ px += word_px;
+ lines.push_back(wrap_substring);
+ return lines;
+}
+
+int TextEdit::get_cursor_wrap_index() const {
+
+ return get_line_wrap_index_at_col(cursor.line, cursor.column);
+}
+
+int TextEdit::get_line_wrap_index_at_col(int p_line, int p_column) const {
+
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
+
+ if (!line_wraps(p_line))
+ return 0;
+
+ // loop through wraps in the line text until we get to the column
+ int wrap_index = 0;
+ int col = 0;
+ Vector<String> rows = get_wrap_rows_text(p_line);
+ for (int i = 0; i < rows.size(); i++) {
+ wrap_index = i;
+ String s = rows[wrap_index];
+ col += s.length();
+ if (col > p_column)
+ break;
+ }
+ return wrap_index;
}
void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
@@ -3587,7 +3799,7 @@ void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
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));
+ cursor.last_fit_x = get_column_x_offset_for_line(cursor.column, cursor.line);
if (p_adjust_viewport)
adjust_viewport_to_cursor();
@@ -3599,7 +3811,7 @@ void TextEdit::cursor_set_column(int p_col, bool p_adjust_viewport) {
}
}
-void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_hidden) {
+void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_hidden, int p_wrap_index) {
if (setting_row)
return;
@@ -3608,8 +3820,8 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_
if (p_row < 0)
p_row = 0;
- if (p_row >= (int)text.size())
- p_row = (int)text.size() - 1;
+ if (p_row >= text.size())
+ p_row = text.size() - 1;
if (!p_can_be_hidden) {
if (is_line_hidden(CLAMP(p_row, 0, text.size() - 1))) {
@@ -3627,7 +3839,18 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_
}
}
cursor.line = p_row;
- cursor.column = get_char_pos_for(cursor.last_fit_x, get_line(cursor.line));
+
+ int n_col = get_char_pos_for_line(cursor.last_fit_x, p_row, p_wrap_index);
+ if (is_wrap_enabled() && p_wrap_index < times_line_wraps(p_row)) {
+ Vector<String> rows = get_wrap_rows_text(p_row);
+ int row_end_col = 0;
+ for (int i = 0; i < p_wrap_index + 1; i++) {
+ row_end_col += rows[i].length();
+ }
+ if (n_col >= row_end_col)
+ n_col -= 1;
+ }
+ cursor.column = n_col;
if (p_adjust_viewport)
adjust_viewport_to_cursor();
@@ -3684,6 +3907,14 @@ bool TextEdit::cursor_is_block_mode() const {
return block_caret;
}
+void TextEdit::set_right_click_moves_caret(bool p_enable) {
+ right_click_moves_caret = p_enable;
+}
+
+bool TextEdit::is_right_click_moving_caret() const {
+ return right_click_moves_caret;
+}
+
void TextEdit::_v_scroll_input() {
scrolling = false;
}
@@ -3696,9 +3927,25 @@ void TextEdit::_scroll_moved(double p_to_val) {
if (h_scroll->is_visible_in_tree())
cursor.x_ofs = h_scroll->get_value();
if (v_scroll->is_visible_in_tree()) {
- double val = v_scroll->get_value();
- cursor.line_ofs = num_lines_from(0, (int)floor(val));
- line_scroll_pos = (int)floor(val);
+
+ // set line ofs and wrap ofs
+ int v_scroll_i = floor(get_v_scroll());
+ int sc = 0;
+ int n_line;
+ for (n_line = 0; n_line < text.size(); n_line++) {
+ if (!is_line_hidden(n_line)) {
+ sc++;
+ sc += times_line_wraps(n_line);
+ if (sc > v_scroll_i)
+ break;
+ }
+ }
+ int line_wrap_amount = times_line_wraps(n_line);
+ int wi = line_wrap_amount - (sc - v_scroll_i - 1);
+ wi = CLAMP(wi, 0, line_wrap_amount);
+
+ cursor.line_ofs = n_line;
+ cursor.wrap_ofs = wi;
}
update();
}
@@ -3708,29 +3955,73 @@ 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 TextEdit::get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) const {
- int px = 0;
- int c = 0;
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
- int tab_w = cache.font->get_char_size(' ').width * indent_size;
+ if (line_wraps(p_line)) {
- while (c < p_str.length()) {
+ int line_wrap_amount = times_line_wraps(p_line);
+ int wrap_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width;
+ if (p_wrap_index > line_wrap_amount)
+ p_wrap_index = line_wrap_amount;
+ if (p_wrap_index > 0)
+ p_px -= wrap_offset_px;
+ else
+ p_wrap_index = 0;
+ Vector<String> rows = get_wrap_rows_text(p_line);
+ int c_pos = get_char_pos_for(p_px, rows[p_wrap_index]);
+ for (int i = 0; i < p_wrap_index; i++) {
+ String s = rows[i];
+ c_pos += s.length();
+ }
- int w = 0;
+ return c_pos;
+ } else {
- if (p_str[c] == '\t') {
+ return get_char_pos_for(p_px, text[p_line]);
+ }
+}
- int left = px % tab_w;
- if (left == 0)
- w = tab_w;
- else
- w = tab_w - px % tab_w; // is right...
+int TextEdit::get_column_x_offset_for_line(int p_char, int p_line) const {
- } else {
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
- w = cache.font->get_char_size(p_str[c], p_str[c + 1]).width;
+ if (line_wraps(p_line)) {
+
+ int n_char = p_char;
+ int col = 0;
+ Vector<String> rows = get_wrap_rows_text(p_line);
+ int wrap_index = 0;
+ for (int i = 0; i < rows.size(); i++) {
+ wrap_index = i;
+ String s = rows[wrap_index];
+ col += s.length();
+ if (col > p_char)
+ break;
+ n_char -= s.length();
}
+ int px = get_column_x_offset(n_char, rows[wrap_index]);
+
+ int wrap_offset_px = get_indent_level(p_line) * cache.font->get_char_size(' ').width;
+ if (wrap_index != 0)
+ px += wrap_offset_px;
+
+ return px;
+ } else {
+
+ return get_column_x_offset(p_char, text[p_line]);
+ }
+}
+
+int TextEdit::get_char_pos_for(int p_px, String p_str) const {
+
+ int px = 0;
+ int c = 0;
+
+ while (c < p_str.length()) {
+
+ int w = text.get_char_width(p_str[c], p_str[c + 1], px);
if (p_px < (px + w / 2))
break;
@@ -3741,28 +4032,16 @@ int TextEdit::get_char_pos_for(int p_px, String p_str) const {
return c;
}
-int TextEdit::get_column_x_offset(int p_char, String p_str) {
+int TextEdit::get_column_x_offset(int p_char, String p_str) const {
int px = 0;
- int tab_w = cache.font->get_char_size(' ').width * indent_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;
- }
+ px += text.get_char_width(p_str[i], p_str[i + 1], px);
}
return px;
@@ -3831,20 +4110,20 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
void TextEdit::set_text(String p_text) {
setting_text = true;
- clear();
+ _clear();
_insert_text_at_cursor(p_text);
clear_undo_history();
cursor.column = 0;
cursor.line = 0;
cursor.x_ofs = 0;
cursor.line_ofs = 0;
- line_scroll_pos = 0;
+ cursor.wrap_ofs = 0;
cursor.last_fit_x = 0;
cursor_set_line(0);
cursor_set_column(0);
update();
setting_text = false;
- _text_changed_emit();
+
//get_range()->set(0);
};
@@ -3924,7 +4203,7 @@ void TextEdit::_clear() {
cursor.line = 0;
cursor.x_ofs = 0;
cursor.line_ofs = 0;
- line_scroll_pos = 0;
+ cursor.wrap_ofs = 0;
cursor.last_fit_x = 0;
}
@@ -3946,9 +4225,14 @@ bool TextEdit::is_readonly() const {
return readonly;
}
-void TextEdit::set_wrap(bool p_wrap) {
+void TextEdit::set_wrap_enabled(bool p_wrap_enabled) {
+
+ wrap_enabled = p_wrap_enabled;
+}
+
+bool TextEdit::is_wrap_enabled() const {
- wrap = p_wrap;
+ return wrap_enabled;
}
void TextEdit::set_max_chars(int p_max_chars) {
@@ -3956,6 +4240,11 @@ void TextEdit::set_max_chars(int p_max_chars) {
max_chars = p_max_chars;
}
+int TextEdit::get_max_chars() const {
+
+ return max_chars;
+}
+
void TextEdit::_reset_caret_blink_timer() {
if (caret_blink_enabled) {
caret_blink_timer->stop();
@@ -4010,13 +4299,89 @@ void TextEdit::_update_caches() {
cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons");
cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons");
text.set_font(cache.font);
+
+ if (syntax_highlighter) {
+ syntax_highlighter->_update_cache();
+ }
+}
+
+SyntaxHighlighter *TextEdit::_get_syntax_highlighting() {
+ return syntax_highlighter;
+}
+
+void TextEdit::_set_syntax_highlighting(SyntaxHighlighter *p_syntax_highlighter) {
+ syntax_highlighter = p_syntax_highlighter;
+ if (syntax_highlighter) {
+ syntax_highlighter->set_text_editor(this);
+ syntax_highlighter->_update_cache();
+ }
+ update();
+}
+
+int TextEdit::_is_line_in_region(int p_line) {
+
+ // do we have in cache?
+ if (color_region_cache.has(p_line)) {
+ return color_region_cache[p_line];
+ }
+
+ // if not find the closest line we have
+ int previous_line = p_line - 1;
+ for (previous_line; previous_line > -1; previous_line--) {
+ if (color_region_cache.has(p_line)) {
+ break;
+ }
+ }
+
+ // calculate up to line we need and update the cache along the way.
+ int in_region = color_region_cache[previous_line];
+ if (previous_line == -1) {
+ in_region = -1;
+ }
+ for (int i = previous_line; i < p_line; i++) {
+ const Map<int, Text::ColorRegionInfo> &cri_map = _get_line_color_region_info(i);
+ 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 && !_get_color_region(cri.region).line_only) {
+ if (cri.end || _get_color_region(cri.region).eq) {
+ in_region = -1;
+ }
+ }
+ }
+
+ if (in_region >= 0 && _get_color_region(in_region).line_only) {
+ in_region = -1;
+ }
+
+ color_region_cache[i + 1] = in_region;
+ }
+ return in_region;
+}
+
+TextEdit::ColorRegion TextEdit::_get_color_region(int p_region) const {
+ if (p_region < 0 || p_region >= color_regions.size()) {
+ return ColorRegion();
+ }
+ return color_regions[p_region];
+}
+
+Map<int, TextEdit::Text::ColorRegionInfo> TextEdit::_get_line_color_region_info(int p_line) const {
+ if (p_line < 0 || p_line > text.size() - 1) {
+ return Map<int, Text::ColorRegionInfo>();
+ }
+ return text.get_color_region_info(p_line);
}
void TextEdit::clear_colors() {
keywords.clear();
color_regions.clear();
- text.clear_caches();
+ color_region_cache.clear();
+ text.clear_width_cache();
}
void TextEdit::add_keyword_color(const String &p_keyword, const Color &p_color) {
@@ -4025,10 +4390,36 @@ void TextEdit::add_keyword_color(const String &p_keyword, const Color &p_color)
update();
}
+bool TextEdit::has_keyword_color(String p_keyword) const {
+ return keywords.has(p_keyword);
+}
+
+Color TextEdit::get_keyword_color(String p_keyword) const {
+ return keywords[p_keyword];
+}
+
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();
+ text.clear_width_cache();
+ update();
+}
+
+void TextEdit::add_member_keyword(const String &p_keyword, const Color &p_color) {
+ member_keywords[p_keyword] = p_color;
+ update();
+}
+
+bool TextEdit::has_member_color(String p_member) const {
+ return member_keywords.has(p_member);
+}
+
+Color TextEdit::get_member_color(String p_member) const {
+ return member_keywords[p_member];
+}
+
+void TextEdit::clear_member_keywords() {
+ member_keywords.clear();
update();
}
@@ -4060,7 +4451,7 @@ void TextEdit::cut() {
backspace_at_cursor();
update();
cursor_set_line(cursor.line + 1);
- cut_copy_line = true;
+ cut_copy_line = clipboard;
} else {
@@ -4074,7 +4465,7 @@ void TextEdit::cut() {
selection.active = false;
selection.selecting_mode = Selection::MODE_NONE;
update();
- cut_copy_line = false;
+ cut_copy_line = "";
}
}
@@ -4083,11 +4474,11 @@ void TextEdit::copy() {
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;
+ cut_copy_line = clipboard;
} 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;
+ cut_copy_line = "";
}
}
@@ -4095,6 +4486,7 @@ void TextEdit::paste() {
String clipboard = OS::get_singleton()->get_clipboard();
+ begin_complex_operation();
if (selection.active) {
selection.active = false;
@@ -4103,7 +4495,7 @@ void TextEdit::paste() {
cursor_set_line(selection.from_line);
cursor_set_column(selection.from_column);
- } else if (cut_copy_line) {
+ } else if (!cut_copy_line.empty() && cut_copy_line == clipboard) {
cursor_set_column(0);
String ins = "\n";
@@ -4111,6 +4503,8 @@ void TextEdit::paste() {
}
_insert_text_at_cursor(clipboard);
+ end_complex_operation();
+
update();
}
@@ -4144,11 +4538,15 @@ void TextEdit::select(int p_from_line, int p_from_column, int p_to_line, int p_t
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_from_column < 0)
+ p_from_column = 0;
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();
+ if (p_to_column < 0)
+ p_to_column = 0;
selection.from_line = p_from_line;
selection.from_column = p_from_column;
@@ -4322,7 +4720,7 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l
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
+ //search through the whole document, but start by current line
int line = p_from_line;
int pos = -1;
@@ -4367,31 +4765,44 @@ bool TextEdit::search(const String &p_key, uint32_t p_search_flags, int p_from_l
int pos_from = 0;
int last_pos = -1;
- while ((last_pos = (p_search_flags & SEARCH_MATCH_CASE) ? text_line.find(p_key, pos_from) : text_line.findn(p_key, pos_from)) != -1) {
- if (p_search_flags & SEARCH_BACKWARDS) {
+ while (true) {
- if (last_pos > from_column)
- break;
- pos = last_pos;
+ while ((last_pos = (p_search_flags & SEARCH_MATCH_CASE) ? text_line.find(p_key, pos_from) : text_line.findn(p_key, pos_from)) != -1) {
- } else {
+ if (p_search_flags & SEARCH_BACKWARDS) {
- if (last_pos >= from_column) {
+ if (last_pos > from_column)
+ break;
pos = last_pos;
- break;
+
+ } else {
+
+ if (last_pos >= from_column) {
+ pos = last_pos;
+ break;
+ }
}
+
+ pos_from = last_pos + p_key.length();
}
- pos_from = last_pos + p_key.length();
- }
+ bool is_match = true;
+
+ if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) {
+ //validate for whole words
+ if (pos > 0 && _is_text_char(text_line[pos - 1]))
+ is_match = false;
+ else if (pos + p_key.length() < text_line.length() && _is_text_char(text_line[pos + p_key.length()]))
+ is_match = false;
+ }
+
+ if (is_match || last_pos == -1 || pos == -1) {
+ break;
+ }
- if (pos != -1 && (p_search_flags & SEARCH_WHOLE_WORDS)) {
- //validate for whole words
- if (pos > 0 && _is_text_char(text_line[pos - 1]))
- pos = -1;
- else if (_is_text_char(text_line[pos + p_key.length()]))
- pos = -1;
+ pos_from = pos + 1;
+ pos = -1;
}
if (pos != -1)
@@ -4487,36 +4898,101 @@ void TextEdit::unhide_all_lines() {
update();
}
-int TextEdit::num_lines_from(int p_line_from, int unhidden_amount) const {
+int TextEdit::num_lines_from(int p_line_from, int visible_amount) const {
- // returns the number of hidden and unhidden lines from p_line_from to p_line_from + amount of visible lines
- ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(unhidden_amount));
+ // returns the number of lines (hidden and unhidden) from p_line_from to (p_line_from + visible_amount of unhidden lines)
+ ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(visible_amount));
if (!is_hiding_enabled())
- return ABS(unhidden_amount);
+ return ABS(visible_amount);
+
int num_visible = 0;
int num_total = 0;
- if (unhidden_amount >= 0) {
+ if (visible_amount >= 0) {
for (int i = p_line_from; i < text.size(); i++) {
num_total++;
- if (!is_line_hidden(i))
+ if (!is_line_hidden(i)) {
num_visible++;
- if (num_visible >= unhidden_amount)
+ }
+ if (num_visible >= visible_amount)
break;
}
} else {
- unhidden_amount = ABS(unhidden_amount);
+ visible_amount = ABS(visible_amount);
for (int i = p_line_from; i >= 0; i--) {
num_total++;
- if (!is_line_hidden(i))
+ if (!is_line_hidden(i)) {
num_visible++;
- if (num_visible >= unhidden_amount)
+ }
+ if (num_visible >= visible_amount)
break;
}
}
return num_total;
}
+int TextEdit::num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const {
+
+ // returns the number of lines (hidden and unhidden) from (p_line_from + p_wrap_index_from) row to (p_line_from + visible_amount of unhidden and wrapped rows)
+ // wrap index is set to the wrap index of the last line
+ wrap_index = 0;
+ ERR_FAIL_INDEX_V(p_line_from, text.size(), ABS(visible_amount));
+
+ if (!is_hiding_enabled() && !is_wrap_enabled())
+ return ABS(visible_amount);
+
+ int num_visible = 0;
+ int num_total = 0;
+ if (visible_amount == 0) {
+ num_total = 0;
+ wrap_index = 0;
+ } else if (visible_amount > 0) {
+ int i;
+ num_visible -= p_wrap_index_from;
+ for (i = p_line_from; i < text.size(); i++) {
+ num_total++;
+ if (!is_line_hidden(i)) {
+ num_visible++;
+ num_visible += times_line_wraps(i);
+ }
+ if (num_visible >= visible_amount)
+ break;
+ }
+ wrap_index = times_line_wraps(MIN(i, text.size() - 1)) - (num_visible - visible_amount);
+ } else {
+ visible_amount = ABS(visible_amount);
+ int i;
+ num_visible -= times_line_wraps(p_line_from) - p_wrap_index_from;
+ for (i = p_line_from; i >= 0; i--) {
+ num_total++;
+ if (!is_line_hidden(i)) {
+ num_visible++;
+ num_visible += times_line_wraps(i);
+ }
+ if (num_visible >= visible_amount)
+ break;
+ }
+ wrap_index = (num_visible - visible_amount);
+ }
+ wrap_index = MAX(wrap_index, 0);
+ return num_total;
+}
+
+int TextEdit::get_last_unhidden_line() const {
+
+ // returns the last line in the text that is not hidden
+ if (!is_hiding_enabled())
+ return text.size() - 1;
+
+ int last_line;
+ for (last_line = text.size() - 1; last_line > 0; last_line--) {
+ if (!is_line_hidden(last_line)) {
+ break;
+ }
+ }
+ return last_line;
+}
+
int TextEdit::get_indent_level(int p_line) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
@@ -4530,13 +5006,36 @@ int TextEdit::get_indent_level(int p_line) const {
tab_count++;
} else if (text[p_line][i] == ' ') {
whitespace_count++;
- } else if (text[p_line][i] == '#') {
+ } else {
break;
+ }
+ }
+ return tab_count * indent_size + whitespace_count;
+}
+
+bool TextEdit::is_line_comment(int p_line) const {
+
+ // checks to see if this line is the start of a comment
+ ERR_FAIL_INDEX_V(p_line, text.size(), false);
+
+ const Map<int, Text::ColorRegionInfo> &cri_map = text.get_color_region_info(p_line);
+
+ int line_length = text[p_line].size();
+ for (int i = 0; i < line_length - 1; i++) {
+ if (_is_symbol(text[p_line][i]) && cri_map.has(i)) {
+ const Text::ColorRegionInfo &cri = cri_map[i];
+ if (color_regions[cri.region].begin_key == "#" || color_regions[cri.region].begin_key == "//") {
+ return true;
+ } else {
+ return false;
+ }
+ } else if (_is_whitespace(text[p_line][i])) {
+ continue;
} else {
break;
}
}
- return tab_count + whitespace_count / indent_size;
+ return false;
}
bool TextEdit::can_fold(int p_line) const {
@@ -4552,6 +5051,8 @@ bool TextEdit::can_fold(int p_line) const {
return false;
if (is_line_hidden(p_line))
return false;
+ if (is_line_comment(p_line))
+ return false;
int start_indent = get_indent_level(p_line);
@@ -4559,10 +5060,13 @@ bool TextEdit::can_fold(int p_line) const {
if (text[i].size() == 0)
continue;
int next_indent = get_indent_level(i);
- if (next_indent > start_indent)
+ if (is_line_comment(i)) {
+ continue;
+ } else if (next_indent > start_indent) {
return true;
- else
+ } else {
return false;
+ }
}
return false;
@@ -4591,7 +5095,9 @@ void TextEdit::fold_line(int p_line) {
int last_line = start_indent;
for (int i = p_line + 1; i < text.size(); i++) {
if (text[i].strip_edges().size() != 0) {
- if (get_indent_level(i) > start_indent) {
+ if (is_line_comment(i)) {
+ continue;
+ } else if (get_indent_level(i) > start_indent) {
last_line = i;
} else {
break;
@@ -4712,6 +5218,8 @@ void TextEdit::undo() {
else
undo_stack_pos = undo_stack_pos->prev();
+ deselect();
+
TextOperation op = undo_stack_pos->get();
_do_text_op(op, true);
current_op.version = op.prev_version;
@@ -4746,6 +5254,8 @@ void TextEdit::redo() {
if (undo_stack_pos == NULL)
return; //nothing to do.
+ deselect();
+
TextOperation op = undo_stack_pos->get();
_do_text_op(op, false);
current_op.version = op.version;
@@ -4830,6 +5340,11 @@ void TextEdit::set_indent_size(const int p_size) {
update();
}
+int TextEdit::get_indent_size() {
+
+ return indent_size;
+}
+
void TextEdit::set_draw_tabs(bool p_draw) {
draw_tabs = p_draw;
@@ -4843,6 +5358,7 @@ bool TextEdit::is_drawing_tabs() const {
void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
override_selected_font_color = p_override_selected_font_color;
}
+
bool TextEdit::is_overriding_selected_font_color() const {
return override_selected_font_color;
}
@@ -4863,58 +5379,143 @@ bool TextEdit::is_insert_text_operation() {
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 {
+double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
- return v_scroll->get_value();
-}
-void TextEdit::set_v_scroll(int p_scroll) {
+ if (!is_wrap_enabled() && !is_hiding_enabled())
+ return p_line;
- if (p_scroll < 0) {
- p_scroll = 0;
- }
- if (!scroll_past_end_of_file_enabled) {
- if (p_scroll + get_visible_rows() > get_total_unhidden_rows()) {
- int num_rows = num_lines_from(CLAMP(p_scroll, 0, text.size() - 1), MIN(get_visible_rows(), text.size() - 1 - p_scroll));
- p_scroll = text.size() - num_rows;
+ // count the number of visible lines up to this line
+ double new_line_scroll_pos = 0;
+ int to = CLAMP(p_line, 0, text.size() - 1);
+ for (int i = 0; i < to; i++) {
+ if (!text.is_hidden(i)) {
+ new_line_scroll_pos++;
+ new_line_scroll_pos += times_line_wraps(i);
}
}
+ new_line_scroll_pos += p_wrap_index;
+ return new_line_scroll_pos;
+}
+
+void TextEdit::set_line_as_first_visible(int p_line, int p_wrap_index) {
+
+ set_v_scroll(get_scroll_pos_for_line(p_line, p_wrap_index));
+}
+
+void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) {
+
+ int visible_rows = get_visible_rows();
+ int wi;
+ int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -visible_rows / 2, wi) + 1;
+
+ set_v_scroll(get_scroll_pos_for_line(first_line, wi));
+}
+
+void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) {
+
+ int wi;
+ int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -get_visible_rows() - 1, wi) + 1;
+
+ set_v_scroll(get_scroll_pos_for_line(first_line, wi) + get_visible_rows_offset());
+}
+
+int TextEdit::get_first_visible_line() const {
+
+ return CLAMP(cursor.line_ofs, 0, text.size() - 1);
+}
+
+int TextEdit::get_last_visible_line() const {
+
+ int first_vis_line = get_first_visible_line();
+ int last_vis_line = 0;
+ int wi;
+ last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1;
+ last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1);
+ return last_vis_line;
+}
+
+int TextEdit::get_last_visible_line_wrap_index() const {
+
+ int first_vis_line = get_first_visible_line();
+ int last_vis_line = 0;
+ int wi;
+ last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1;
+ return wi;
+}
+
+double TextEdit::get_visible_rows_offset() const {
+
+ double total = cache.size.height;
+ total -= cache.style_normal->get_minimum_size().height;
+ if (h_scroll->is_visible_in_tree())
+ total -= h_scroll->get_size().height;
+ total /= (double)get_row_height();
+ total = total - floor(total);
+ total = -CLAMP(total, 0.001, 1) + 1;
+ return total;
+}
+
+double TextEdit::get_v_scroll_offset() const {
+
+ double val = get_v_scroll() - floor(get_v_scroll());
+ return CLAMP(val, 0, 1);
+}
+
+double TextEdit::get_v_scroll() const {
+
+ return v_scroll->get_value();
+}
+
+void TextEdit::set_v_scroll(double p_scroll) {
+
v_scroll->set_value(p_scroll);
- cursor.line_ofs = num_lines_from(0, p_scroll);
- line_scroll_pos = p_scroll;
+ int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
+ if (p_scroll >= max_v_scroll - 1.0)
+ _scroll_moved(v_scroll->get_value());
}
int TextEdit::get_h_scroll() const {
return h_scroll->get_value();
}
+
void TextEdit::set_h_scroll(int p_scroll) {
+ if (p_scroll < 0) {
+ p_scroll = 0;
+ }
h_scroll->set_value(p_scroll);
}
void TextEdit::set_smooth_scroll_enabled(bool p_enable) {
+
v_scroll->set_smooth_scroll_enabled(p_enable);
smooth_scroll_enabled = p_enable;
}
bool TextEdit::is_smooth_scroll_enabled() const {
+
return smooth_scroll_enabled;
}
void TextEdit::set_v_scroll_speed(float p_speed) {
+
v_scroll_speed = p_speed;
}
float TextEdit::get_v_scroll_speed() const {
+
return v_scroll_speed;
}
@@ -4946,7 +5547,7 @@ void TextEdit::_confirm_completion() {
void TextEdit::_cancel_code_hint() {
- VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 0);
+ VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0);
raised_from_completion = false;
completion_hint = "";
update();
@@ -4954,7 +5555,7 @@ void TextEdit::_cancel_code_hint() {
void TextEdit::_cancel_completion() {
- VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 0);
+ VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 0);
raised_from_completion = false;
if (!completion_active)
return;
@@ -5019,7 +5620,7 @@ void TextEdit::_update_completion_candidates() {
} else {
- while (cofs > 0 && l[cofs - 1] > 32 && _is_completable(l[cofs - 1])) {
+ while (cofs > 0 && l[cofs - 1] > 32 && (l[cofs - 1] == '/' || _is_completable(l[cofs - 1]))) {
s = String::chr(l[cofs - 1]) + s;
if (l[cofs - 1] == '\'' || l[cofs - 1] == '"' || l[cofs - 1] == '$')
break;
@@ -5129,7 +5730,7 @@ void TextEdit::query_code_comple() {
void TextEdit::set_code_hint(const String &p_hint) {
- VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 1);
+ VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1);
raised_from_completion = true;
completion_hint = p_hint;
completion_hint_offset = -0xFFFF;
@@ -5138,7 +5739,7 @@ void TextEdit::set_code_hint(const String &p_hint) {
void TextEdit::code_complete(const Vector<String> &p_strings, bool p_forced) {
- VisualServer::get_singleton()->canvas_item_set_z(get_canvas_item(), 1);
+ VisualServer::get_singleton()->canvas_item_set_z_index(get_canvas_item(), 1);
raised_from_completion = true;
completion_strings = p_strings;
completion_active = true;
@@ -5157,12 +5758,8 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
String s = text[row];
if (s.length() == 0)
return "";
- 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
+ int beg, end;
+ if (select_word(s, col, beg, end)) {
bool inside_quotes = false;
int qbegin = 0, qend = 0;
@@ -5181,16 +5778,6 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
}
}
- 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;
-
return s.substr(beg, end - beg);
}
@@ -5207,22 +5794,8 @@ String TextEdit::get_tooltip(const Point2 &p_pos) const {
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;
+ int beg, end;
+ if (select_word(s, col, beg, end)) {
String tt = tooltip_obj->call(tooltip_func, s.substr(beg, end - beg), tooltip_ud);
@@ -5422,7 +5995,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line);
ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true));
- ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("cursor_set_line", "line", "adjust_viewport", "can_be_hidden", "wrap_index"), &TextEdit::cursor_set_line, DEFVAL(true), DEFVAL(true), DEFVAL(0));
ClassDB::bind_method(D_METHOD("cursor_get_column"), &TextEdit::cursor_get_column);
ClassDB::bind_method(D_METHOD("cursor_get_line"), &TextEdit::cursor_get_line);
@@ -5433,19 +6006,26 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("cursor_set_block_mode", "enable"), &TextEdit::cursor_set_block_mode);
ClassDB::bind_method(D_METHOD("cursor_is_block_mode"), &TextEdit::cursor_is_block_mode);
+ ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret);
+ ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret);
+
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
- ClassDB::bind_method(D_METHOD("set_wrap", "enable"), &TextEdit::set_wrap);
- ClassDB::bind_method(D_METHOD("set_max_chars", "amount"), &TextEdit::set_max_chars);
+ ClassDB::bind_method(D_METHOD("set_wrap_enabled", "enable"), &TextEdit::set_wrap_enabled);
+ ClassDB::bind_method(D_METHOD("is_wrap_enabled"), &TextEdit::is_wrap_enabled);
+ // ClassDB::bind_method(D_METHOD("set_max_chars", "amount"), &TextEdit::set_max_chars);
+ // ClassDB::bind_method(D_METHOD("get_max_char"), &TextEdit::get_max_chars);
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &TextEdit::set_context_menu_enabled);
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled);
ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut);
ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy);
ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste);
- ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
+
ClassDB::bind_method(D_METHOD("select", "from_line", "from_column", "to_line", "to_column"), &TextEdit::select);
+ ClassDB::bind_method(D_METHOD("select_all"), &TextEdit::select_all);
+ ClassDB::bind_method(D_METHOD("deselect"), &TextEdit::deselect);
ClassDB::bind_method(D_METHOD("is_selection_active"), &TextEdit::is_selection_active);
ClassDB::bind_method(D_METHOD("get_selection_from_line"), &TextEdit::get_selection_from_line);
@@ -5466,7 +6046,7 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled);
ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled);
ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden);
- ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden);
+ ClassDB::bind_method(D_METHOD("is_line_hidden", "line"), &TextEdit::is_line_hidden);
ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines);
ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines);
ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line);
@@ -5493,6 +6073,8 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_v_scroll_speed"), &TextEdit::get_v_scroll_speed);
ClassDB::bind_method(D_METHOD("add_keyword_color", "keyword", "color"), &TextEdit::add_keyword_color);
+ ClassDB::bind_method(D_METHOD("has_keyword_color", "keyword"), &TextEdit::has_keyword_color);
+ ClassDB::bind_method(D_METHOD("get_keyword_color", "keyword"), &TextEdit::get_keyword_color);
ClassDB::bind_method(D_METHOD("add_color_region", "begin_key", "end_key", "color", "line_only"), &TextEdit::add_color_region, DEFVAL(false));
ClassDB::bind_method(D_METHOD("clear_colors"), &TextEdit::clear_colors);
ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option);
@@ -5509,11 +6091,14 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hiding_enabled"), "set_hiding_enabled", "is_hiding_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_enabled"), "set_wrap_enabled", "is_wrap_enabled");
+ // ADD_PROPERTY(PropertyInfo(Variant::BOOL, "max_chars"), "set_max_chars", "get_max_chars");
ADD_GROUP("Caret", "caret_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled");
- ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.1"), "cursor_set_blink_speed", "cursor_get_blink_speed");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_moving_by_right_click"), "set_right_click_moves_caret", "is_right_click_moving_caret");
ADD_SIGNAL(MethodInfo("cursor_changed"));
ADD_SIGNAL(MethodInfo("text_changed"));
@@ -5541,8 +6126,10 @@ TextEdit::TextEdit() {
draw_caret = true;
max_chars = 0;
clear();
- wrap = false;
+ wrap_enabled = false;
+ wrap_right_offset = 10;
set_focus_mode(FOCUS_ALL);
+ syntax_highlighter = NULL;
_update_caches();
cache.size = Size2(1, 1);
cache.row_height = 1;
@@ -5556,7 +6143,7 @@ TextEdit::TextEdit() {
indent_size = 4;
text.set_indent_size(indent_size);
text.clear();
- //text.insert(1,"Mongolia..");
+ //text.insert(1,"Mongolia...");
//text.insert(2,"PAIS GENEROSO!!");
text.set_color_regions(&color_regions);
@@ -5591,6 +6178,7 @@ TextEdit::TextEdit() {
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", this, "_toggle_draw_caret");
cursor_set_blink_enabled(false);
+ right_click_moves_caret = true;
idle_detect = memnew(Timer);
add_child(idle_detect);
@@ -5645,16 +6233,213 @@ TextEdit::TextEdit() {
context_menu_enabled = true;
menu = memnew(PopupMenu);
add_child(menu);
- menu->add_item(TTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
- menu->add_item(TTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
- menu->add_item(TTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
+ menu->add_item(RTR("Cut"), MENU_CUT, KEY_MASK_CMD | KEY_X);
+ menu->add_item(RTR("Copy"), MENU_COPY, KEY_MASK_CMD | KEY_C);
+ menu->add_item(RTR("Paste"), MENU_PASTE, KEY_MASK_CMD | KEY_V);
menu->add_separator();
- menu->add_item(TTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
- menu->add_item(TTR("Clear"), MENU_CLEAR);
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, KEY_MASK_CMD | KEY_A);
+ menu->add_item(RTR("Clear"), MENU_CLEAR);
menu->add_separator();
- menu->add_item(TTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
+ menu->add_item(RTR("Undo"), MENU_UNDO, KEY_MASK_CMD | KEY_Z);
menu->connect("id_pressed", this, "menu_option");
}
TextEdit::~TextEdit() {
}
+
+///////////////////////////////////////////////////////////////////////////////
+
+Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int p_line) {
+ if (syntax_highlighter != NULL) {
+ return syntax_highlighter->_get_line_syntax_highlighting(p_line);
+ }
+
+ Map<int, HighlighterInfo> color_map;
+
+ bool prev_is_char = false;
+ bool prev_is_number = false;
+ bool in_keyword = false;
+ bool in_word = false;
+ bool in_function_name = false;
+ bool in_member_variable = false;
+ bool is_hex_notation = false;
+ Color keyword_color;
+ Color color;
+
+ int in_region = _is_line_in_region(p_line);
+ int deregion = 0;
+
+ const Map<int, TextEdit::Text::ColorRegionInfo> cri_map = text.get_color_region_info(p_line);
+ const String &str = text[p_line];
+ Color prev_color;
+ for (int j = 0; j < str.length(); j++) {
+ HighlighterInfo highlighter_info;
+
+ if (deregion > 0) {
+ deregion--;
+ if (deregion == 0) {
+ in_region = -1;
+ }
+ }
+
+ if (deregion != 0) {
+ if (color != prev_color) {
+ prev_color = color;
+ highlighter_info.color = color;
+ color_map[j] = highlighter_info;
+ }
+ continue;
+ }
+
+ color = cache.font_color;
+
+ bool is_char = _is_text_char(str[j]);
+ bool is_symbol = _is_symbol(str[j]);
+ bool is_number = _is_number(str[j]);
+
+ // allow ABCDEF in hex notation
+ if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) {
+ is_number = true;
+ } else {
+ is_hex_notation = false;
+ }
+
+ // check for dot or underscore or 'x' for hex notation in floating point number
+ if ((str[j] == '.' || str[j] == 'x' || str[j] == '_') && !in_word && prev_is_number && !is_number) {
+ is_number = true;
+ is_symbol = false;
+ is_char = false;
+
+ if (str[j] == 'x' && str[j - 1] == '0') {
+ is_hex_notation = true;
+ }
+ }
+
+ if (!in_word && _is_char(str[j]) && !is_number) {
+ in_word = true;
+ }
+
+ if ((in_keyword || in_word) && !is_hex_notation) {
+ is_number = false;
+ }
+
+ if (is_symbol && str[j] != '.' && in_word) {
+ in_word = false;
+ }
+
+ if (is_symbol && cri_map.has(j)) {
+ const TextEdit::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 (to < str.length() && _is_text_char(str[to]))
+ 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) {
+ col = member_keywords.custom_getptr(range, hash);
+
+ if (col) {
+ for (int k = j - 1; k >= 0; k--) {
+ if (str[k] == '.') {
+ col = NULL; //member indexing not allowed
+ break;
+ } else if (str[k] > 32) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (col) {
+ in_keyword = true;
+ keyword_color = *col;
+ }
+ }
+
+ if (!in_function_name && in_word && !in_keyword) {
+
+ int k = j;
+ while (k < str.length() && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
+ k++;
+ }
+
+ // check for space between name and bracket
+ while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
+ k++;
+ }
+
+ if (str[k] == '(') {
+ in_function_name = true;
+ }
+ }
+
+ if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) {
+ int k = j;
+ while (k > 0 && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
+ k--;
+ }
+
+ if (str[k] == '.') {
+ in_member_variable = true;
+ }
+ }
+
+ if (is_symbol) {
+ in_function_name = false;
+ in_member_variable = false;
+ }
+
+ if (in_region >= 0)
+ color = color_regions[in_region].color;
+ else if (in_keyword)
+ color = keyword_color;
+ else if (in_member_variable)
+ color = cache.member_variable_color;
+ else if (in_function_name)
+ color = cache.function_color;
+ else if (is_symbol)
+ color = cache.symbol_color;
+ else if (is_number)
+ color = cache.number_color;
+
+ prev_is_char = is_char;
+ prev_is_number = is_number;
+
+ if (color != prev_color) {
+ prev_color = color;
+ highlighter_info.color = color;
+ color_map[j] = highlighter_info;
+ }
+ }
+
+ return color_map;
+}
+
+void SyntaxHighlighter::set_text_editor(TextEdit *p_text_editor) {
+ text_editor = p_text_editor;
+}
+
+TextEdit *SyntaxHighlighter::get_text_editor() {
+ return text_editor;
+}
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index dd305d5822..5c82d1ac20 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TEXT_EDIT_H
#define TEXT_EDIT_H
@@ -35,14 +36,91 @@
#include "scene/gui/scroll_bar.h"
#include "scene/main/timer.h"
+class SyntaxHighlighter;
+
class TextEdit : public Control {
- GDCLASS(TextEdit, Control);
+ GDCLASS(TextEdit, Control)
+
+public:
+ struct HighlighterInfo {
+ Color color;
+ };
+
+ struct ColorRegion {
+
+ Color color;
+ String begin_key;
+ String end_key;
+ bool line_only;
+ bool eq;
+ ColorRegion(const String &p_begin_key = "", const String &p_end_key = "", const Color &p_color = Color(), bool p_line_only = false) {
+ begin_key = p_begin_key;
+ end_key = p_end_key;
+ color = p_color;
+ line_only = p_line_only || p_end_key == "";
+ eq = begin_key == end_key;
+ }
+ };
+
+ class Text {
+ public:
+ struct ColorRegionInfo {
+
+ int region;
+ bool end;
+ };
+
+ struct Line {
+ int width_cache : 24;
+ bool marked : 1;
+ bool breakpoint : 1;
+ bool hidden : 1;
+ int wrap_amount_cache : 24;
+ Map<int, ColorRegionInfo> region_info;
+ String data;
+ };
+
+ private:
+ const Vector<ColorRegion> *color_regions;
+ mutable Vector<Line> text;
+ Ref<Font> font;
+ int indent_size;
+
+ void _update_line_cache(int p_line) const;
+ public:
+ void set_indent_size(int p_indent_size);
+ void set_font(const Ref<Font> &p_font);
+ void set_color_regions(const Vector<ColorRegion> *p_regions) { color_regions = p_regions; }
+ int get_line_width(int p_line) const;
+ int get_max_width(bool p_exclude_hidden = false) const;
+ int get_char_width(CharType c, CharType next_c, int px) const;
+ void set_line_wrap_amount(int p_line, int p_wrap_amount) const;
+ int get_line_wrap_amount(int p_line) const;
+ const Map<int, ColorRegionInfo> &get_color_region_info(int p_line) const;
+ void set(int p_line, const String &p_text);
+ void set_marked(int p_line, bool p_marked) { text[p_line].marked = p_marked; }
+ bool is_marked(int p_line) const { return text[p_line].marked; }
+ void set_breakpoint(int p_line, bool p_breakpoint) { text[p_line].breakpoint = p_breakpoint; }
+ bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; }
+ void set_hidden(int p_line, bool p_hidden) { text[p_line].hidden = p_hidden; }
+ bool is_hidden(int p_line) const { return text[p_line].hidden; }
+ void insert(int p_at, const String &p_text);
+ void remove(int p_at);
+ int size() const { return text.size(); }
+ void clear();
+ void clear_width_cache();
+ void clear_wrap_cache();
+ _FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
+ Text() { indent_size = 4; }
+ };
+
+private:
struct Cursor {
int last_fit_x;
int line, column; ///< cursor
- int x_ofs, line_ofs;
+ int x_ofs, line_ofs, wrap_ofs;
} cursor;
struct Selection {
@@ -114,69 +192,7 @@ class TextEdit : public Control {
Size2 size;
} cache;
- struct ColorRegion {
-
- Color color;
- String begin_key;
- String end_key;
- bool line_only;
- bool eq;
- ColorRegion(const String &p_begin_key = "", const String &p_end_key = "", const Color &p_color = Color(), bool p_line_only = false) {
- begin_key = p_begin_key;
- end_key = p_end_key;
- color = p_color;
- line_only = p_line_only || p_end_key == "";
- eq = begin_key == end_key;
- }
- };
-
- class Text {
- public:
- struct ColorRegionInfo {
-
- int region;
- bool end;
- };
-
- struct Line {
- int width_cache : 24;
- bool marked : 1;
- bool breakpoint : 1;
- bool hidden : 1;
- Map<int, ColorRegionInfo> region_info;
- String data;
- };
-
- private:
- const Vector<ColorRegion> *color_regions;
- mutable Vector<Line> text;
- Ref<Font> font;
- int indent_size;
-
- void _update_line_cache(int p_line) const;
-
- public:
- void set_indent_size(int p_indent_size);
- void set_font(const Ref<Font> &p_font);
- void set_color_regions(const Vector<ColorRegion> *p_regions) { color_regions = p_regions; }
- int get_line_width(int p_line) const;
- int get_max_width(bool p_exclude_hidden = false) const;
- const Map<int, ColorRegionInfo> &get_color_region_info(int p_line);
- void set(int p_line, const String &p_text);
- void set_marked(int p_line, bool p_marked) { text[p_line].marked = p_marked; }
- bool is_marked(int p_line) const { return text[p_line].marked; }
- void set_breakpoint(int p_line, bool p_breakpoint) { text[p_line].breakpoint = p_breakpoint; }
- bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; }
- void set_hidden(int p_line, bool p_hidden) { text[p_line].hidden = p_hidden; }
- bool is_hidden(int p_line) const { return text[p_line].hidden; }
- void insert(int p_at, const String &p_text);
- void remove(int p_at);
- 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; }
- Text() { indent_size = 4; }
- };
+ Map<int, int> color_region_cache;
struct TextOperation {
@@ -208,7 +224,11 @@ class TextEdit : public Control {
void _do_text_op(const TextOperation &p_op, bool p_reverse);
//syntax coloring
+ SyntaxHighlighter *syntax_highlighter;
HashMap<String, Color> keywords;
+ HashMap<String, Color> member_keywords;
+
+ Map<int, HighlighterInfo> _get_line_syntax_highlighting(int p_line);
Vector<ColorRegion> color_regions;
@@ -246,9 +266,13 @@ class TextEdit : public Control {
bool draw_caret;
bool window_has_focus;
bool block_caret;
+ bool right_click_moves_caret;
+
+ bool wrap_enabled;
+ int wrap_at;
+ int wrap_right_offset;
bool setting_row;
- bool wrap;
bool draw_tabs;
bool override_selected_font_color;
bool cursor_changed_dirty;
@@ -270,7 +294,7 @@ class TextEdit : public Control {
bool brace_matching_enabled;
bool highlight_current_line;
bool auto_indent;
- bool cut_copy_line;
+ String cut_copy_line;
bool insert_mode;
bool select_identifiers_enabled;
@@ -305,19 +329,34 @@ class TextEdit : public Control {
int search_result_line;
int search_result_col;
- double line_scroll_pos;
-
bool context_menu_enabled;
int get_visible_rows() const;
- int get_total_unhidden_rows() const;
- double get_line_scroll_pos(bool p_recalculate = false) const;
- void update_line_scroll_pos();
-
+ int get_total_visible_rows() const;
+
+ void update_cursor_wrap_offset();
+ void update_wrap_at();
+ bool line_wraps(int line) const;
+ int times_line_wraps(int line) const;
+ Vector<String> get_wrap_rows_text(int p_line) const;
+ int get_cursor_wrap_index() const;
+ int get_line_wrap_index_at_col(int p_line, int p_column) const;
int get_char_count();
+ double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const;
+ void set_line_as_first_visible(int p_line, int p_wrap_index = 0);
+ void set_line_as_center_visible(int p_line, int p_wrap_index = 0);
+ void set_line_as_last_visible(int p_line, int p_wrap_index = 0);
+ int get_first_visible_line() const;
+ int get_last_visible_line() const;
+ int get_last_visible_line_wrap_index() const;
+ double get_visible_rows_offset() const;
+ double get_v_scroll_offset() const;
+
+ int get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const;
+ int get_column_x_offset_for_line(int p_char, int p_line) const;
int get_char_pos_for(int p_px, String p_str) const;
- int get_column_x_offset(int p_char, String p_str);
+ int get_column_x_offset(int p_char, String p_str) const;
void adjust_viewport_to_cursor();
double get_scroll_line_diff() const;
@@ -352,6 +391,7 @@ class TextEdit : public Control {
void _update_caches();
void _cursor_changed_emit();
void _text_changed_emit();
+ void _line_edited_from(int p_line);
void _push_current_op();
@@ -388,6 +428,13 @@ protected:
static void _bind_methods();
public:
+ SyntaxHighlighter *_get_syntax_highlighting();
+ void _set_syntax_highlighting(SyntaxHighlighter *p_syntax_highlighter);
+
+ int _is_line_in_region(int p_line);
+ ColorRegion _get_color_region(int p_region) const;
+ Map<int, Text::ColorRegionInfo> _get_line_color_region_info(int p_line) const;
+
enum MenuItems {
MENU_CUT,
MENU_COPY,
@@ -431,7 +478,10 @@ public:
bool is_line_hidden(int p_line) const;
void fold_all_lines();
void unhide_all_lines();
- int num_lines_from(int p_line_from, int unhidden_amount) const;
+ int num_lines_from(int p_line_from, int visible_amount) const;
+ int num_lines_from_rows(int p_line_from, int p_wrap_index_from, int visible_amount, int &wrap_index) const;
+ int get_last_unhidden_line() const;
+
bool can_fold(int p_line) const;
bool is_folded(int p_line) const;
void fold_line(int p_line);
@@ -443,9 +493,10 @@ public:
void set_line(int line, String new_text);
void backspace_at_cursor();
- void indent_selection_left();
- void indent_selection_right();
+ void indent_left();
+ void indent_right();
int get_indent_level(int p_line) const;
+ bool is_line_comment(int p_line) const;
inline void set_scroll_pass_end_of_file(bool p_enabled) {
scroll_past_end_of_file_enabled = p_enabled;
@@ -467,7 +518,7 @@ public:
void center_viewport_to_cursor();
void cursor_set_column(int p_col, bool p_adjust_viewport = true);
- void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true);
+ void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0);
int cursor_get_column() const;
int cursor_get_line() const;
@@ -481,11 +532,17 @@ public:
void cursor_set_block_mode(const bool p_enable);
bool cursor_is_block_mode() const;
+ void set_right_click_moves_caret(bool p_enable);
+ bool is_right_click_moving_caret() const;
+
void set_readonly(bool p_readonly);
bool is_readonly() const;
void set_max_chars(int p_max_chars);
- void set_wrap(bool p_wrap);
+ int get_max_chars() const;
+
+ void set_wrap_enabled(bool p_wrap_enabled);
+ bool is_wrap_enabled() const;
void clear();
@@ -525,6 +582,7 @@ public:
void set_indent_using_spaces(const bool p_use_spaces);
bool is_indent_using_spaces() const;
void set_indent_size(const int p_size);
+ int get_indent_size();
void set_draw_tabs(bool p_draw);
bool is_drawing_tabs() const;
void set_override_selected_font_color(bool p_override_selected_font_color);
@@ -534,11 +592,19 @@ public:
bool is_insert_mode() const;
void add_keyword_color(const String &p_keyword, const Color &p_color);
+ bool has_keyword_color(String p_keyword) const;
+ Color get_keyword_color(String p_keyword) const;
+
void add_color_region(const String &p_begin_key = String(), const String &p_end_key = String(), const Color &p_color = Color(), bool p_line_only = false);
void clear_colors();
- int get_v_scroll() const;
- void set_v_scroll(int p_scroll);
+ void add_member_keyword(const String &p_keyword, const Color &p_color);
+ bool has_member_color(String p_member) const;
+ Color get_member_color(String p_member) const;
+ void clear_member_keywords();
+
+ double get_v_scroll() const;
+ void set_v_scroll(double p_scroll);
int get_h_scroll() const;
void set_h_scroll(int p_scroll);
@@ -607,4 +673,19 @@ public:
VARIANT_ENUM_CAST(TextEdit::MenuItems);
VARIANT_ENUM_CAST(TextEdit::SearchFlags);
+class SyntaxHighlighter {
+protected:
+ TextEdit *text_editor;
+
+public:
+ virtual void _update_cache() = 0;
+ virtual Map<int, TextEdit::HighlighterInfo> _get_line_syntax_highlighting(int p_line) = 0;
+
+ virtual String get_name() = 0;
+ virtual List<String> get_supported_languages() = 0;
+
+ void set_text_editor(TextEdit *p_text_editor);
+ TextEdit *get_text_editor();
+};
+
#endif // TEXT_EDIT_H
diff --git a/scene/gui/texture_button.cpp b/scene/gui/texture_button.cpp
index 77bc876201..6bd3b26280 100644
--- a/scene/gui/texture_button.cpp
+++ b/scene/gui/texture_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,7 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "texture_button.h"
+#include "core/typedefs.h"
+#include <stdlib.h>
Size2 TextureButton::get_minimum_size() const {
@@ -57,10 +60,50 @@ bool TextureButton::has_point(const Point2 &p_point) const {
if (click_mask.is_valid()) {
- Point2i p = p_point;
- if (p.x < 0 || p.x >= click_mask->get_size().width || p.y < 0 || p.y >= click_mask->get_size().height)
+ Point2 point = p_point;
+ Rect2 rect = Rect2();
+ Size2 mask_size = click_mask->get_size();
+
+ if (_tile) {
+ // if the stretch mode is tile we offset the point to keep it inside the mask size
+ rect.size = mask_size;
+ if (_position_rect.has_point(point)) {
+ int cols = (int)Math::ceil(_position_rect.size.x / mask_size.x);
+ int rows = (int)Math::ceil(_position_rect.size.y / mask_size.y);
+ int col = (int)(point.x / mask_size.x) % cols;
+ int row = (int)(point.y / mask_size.y) % rows;
+ point.x -= mask_size.x * col;
+ point.y -= mask_size.y * row;
+ }
+ } else {
+ // we need to transform the point from our scaled / translated image back to our mask image
+ Point2 ofs = _position_rect.position;
+ Size2 scale = mask_size / _position_rect.size;
+
+ switch (stretch_mode) {
+ case STRETCH_KEEP_ASPECT_COVERED: {
+ // if the stretch mode is aspect covered the image uses a texture region so we need to take that into account
+ float min = MIN(scale.x, scale.y);
+ scale.x = min;
+ scale.y = min;
+ ofs -= _texture_region.position / min;
+ } break;
+ }
+
+ // offset and scale the new point position to adjust it to the bitmask size
+ point -= ofs;
+ point *= scale;
+
+ // finally, we need to check if the point is inside a rectangle with a position >= 0,0 and a size <= mask_size
+ rect.position = Point2(MAX(0, _texture_region.position.x), MAX(0, _texture_region.position.y));
+ rect.size = Size2(MIN(mask_size.x, _texture_region.size.x), MIN(mask_size.y, _texture_region.size.y));
+ }
+
+ if (!rect.has_point(point)) {
return false;
+ }
+ Point2i p = point;
return click_mask->get_bit(p);
}
@@ -117,8 +160,8 @@ void TextureButton::_notification(int p_what) {
if (texdraw.is_valid()) {
Point2 ofs;
Size2 size = texdraw->get_size();
- Rect2 tex_regin = Rect2(Point2(), texdraw->get_size());
- bool tile = false;
+ _texture_region = Rect2(Point2(), texdraw->get_size());
+ _tile = false;
if (expand) {
switch (stretch_mode) {
case STRETCH_KEEP:
@@ -129,7 +172,7 @@ void TextureButton::_notification(int p_what) {
break;
case STRETCH_TILE:
size = get_size();
- tile = true;
+ _tile = true;
break;
case STRETCH_KEEP_CENTERED:
ofs = (get_size() - texdraw->get_size()) / 2;
@@ -160,14 +203,15 @@ void TextureButton::_notification(int p_what) {
float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height;
Size2 scaledTexSize = tex_size * scale;
Point2 ofs = ((scaledTexSize - size) / scale).abs() / 2.0f;
- tex_regin = Rect2(ofs, size / scale);
+ _texture_region = Rect2(ofs, size / scale);
} break;
}
}
- if (tile)
- draw_texture_rect(texdraw, Rect2(ofs, size), tile);
+ _position_rect = Rect2(ofs, size);
+ if (_tile)
+ draw_texture_rect(texdraw, _position_rect, _tile);
else
- draw_texture_rect_region(texdraw, Rect2(ofs, size), tex_regin);
+ draw_texture_rect_region(texdraw, _position_rect, _texture_region);
}
if (has_focus() && focused.is_valid()) {
@@ -298,4 +342,8 @@ TextureButton::StretchMode TextureButton::get_stretch_mode() const {
TextureButton::TextureButton() {
expand = false;
stretch_mode = STRETCH_SCALE;
+
+ _texture_region = Rect2();
+ _position_rect = Rect2();
+ _tile = false;
}
diff --git a/scene/gui/texture_button.h b/scene/gui/texture_button.h
index 94f372decf..d42df390e8 100644
--- a/scene/gui/texture_button.h
+++ b/scene/gui/texture_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TEXTURE_BUTTON_H
#define TEXTURE_BUTTON_H
@@ -57,6 +58,10 @@ private:
bool expand;
StretchMode stretch_mode;
+ Rect2 _texture_region;
+ Rect2 _position_rect;
+ bool _tile;
+
protected:
virtual Size2 get_minimum_size() const;
virtual bool has_point(const Point2 &p_point) const;
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index aad7c6b96b..82d983184b 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "texture_progress.h"
#include "engine.h"
@@ -105,6 +106,33 @@ Ref<Texture> TextureProgress::get_progress_texture() const {
return progress;
}
+void TextureProgress::set_tint_under(const Color &p_tint) {
+ tint_under = p_tint;
+ update();
+}
+
+Color TextureProgress::get_tint_under() const {
+ return tint_under;
+}
+
+void TextureProgress::set_tint_progress(const Color &p_tint) {
+ tint_progress = p_tint;
+ update();
+}
+
+Color TextureProgress::get_tint_progress() const {
+ return tint_progress;
+}
+
+void TextureProgress::set_tint_over(const Color &p_tint) {
+ tint_over = p_tint;
+ update();
+}
+
+Color TextureProgress::get_tint_over() const {
+ return tint_over;
+}
+
Point2 TextureProgress::unit_val_to_uv(float val) {
if (progress.is_null())
return Point2();
@@ -116,22 +144,45 @@ Point2 TextureProgress::unit_val_to_uv(float val) {
Point2 p = get_relative_center();
- if (val < 0.125)
- return Point2(p.x + (1 - p.x) * val * 8, 0);
- if (val < 0.25)
- return Point2(1, p.y * (val - 0.125) * 8);
- if (val < 0.375)
- return Point2(1, p.y + (1 - p.y) * (val - 0.25) * 8);
- if (val < 0.5)
- return Point2(1 - (1 - p.x) * (val - 0.375) * 8, 1);
- if (val < 0.625)
- return Point2(p.x * (1 - (val - 0.5) * 8), 1);
- if (val < 0.75)
- return Point2(0, 1 - ((1 - p.y) * (val - 0.625) * 8));
- if (val < 0.875)
- return Point2(0, p.y - p.y * (val - 0.75) * 8);
- else
- return Point2(p.x * (val - 0.875) * 8, 0);
+ // Minimal version of Liang-Barsky clipping algorithm
+ float angle = (val * Math_TAU) - Math_PI * 0.5;
+ Point2 dir = Vector2(Math::cos(angle), Math::sin(angle));
+ float t1 = 1.0;
+ float cp;
+ float cq;
+ float cr;
+ float edgeLeft = 0.0;
+ float edgeRight = 1.0;
+ float edgeBottom = 0.0;
+ float edgeTop = 1.0;
+
+ for (int edge = 0; edge < 4; edge++) {
+ if (edge == 0) {
+ if (dir.x > 0)
+ continue;
+ cp = -dir.x;
+ cq = -(edgeLeft - p.x);
+ } else if (edge == 1) {
+ if (dir.x < 0)
+ continue;
+ cp = dir.x;
+ cq = (edgeRight - p.x);
+ } else if (edge == 2) {
+ if (dir.y > 0)
+ continue;
+ cp = -dir.y;
+ cq = -(edgeBottom - p.y);
+ } else if (edge == 3) {
+ if (dir.y < 0)
+ continue;
+ cp = dir.y;
+ cq = (edgeTop - p.y);
+ }
+ cr = cq / cp;
+ if (cr >= 0 && cr < t1)
+ t1 = cr;
+ }
+ return (p + t1 * dir);
}
Point2 TextureProgress::get_relative_center() {
@@ -146,7 +197,7 @@ Point2 TextureProgress::get_relative_center() {
return p;
}
-void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, FillMode p_mode, double p_ratio) {
+void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate) {
Vector2 texture_size = p_texture->get_size();
Vector2 topleft = Vector2(stretch_margin[MARGIN_LEFT], stretch_margin[MARGIN_TOP]);
Vector2 bottomright = Vector2(stretch_margin[MARGIN_RIGHT], stretch_margin[MARGIN_BOTTOM]);
@@ -157,7 +208,7 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F
if (p_ratio < 1.0) {
// Drawing a partially-filled 9-patch is a little tricky -
// texture is divided by 3 sections toward fill direction,
- // then middle section is streching while the other two aren't.
+ // then middle section is stretching while the other two aren't.
double width_total = 0.0;
double width_texture = 0.0;
@@ -216,7 +267,7 @@ void TextureProgress::draw_nine_patch_stretched(const Ref<Texture> &p_texture, F
}
RID ci = get_canvas_item();
- VS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright);
+ VS::get_singleton()->canvas_item_add_nine_patch(ci, dst_rect, src_rect, p_texture->get_rid(), topleft, bottomright, VS::NINE_PATCH_STRETCH, VS::NINE_PATCH_STRETCH, true, p_modulate);
}
void TextureProgress::_notification(int p_what) {
@@ -227,42 +278,42 @@ void TextureProgress::_notification(int p_what) {
if (nine_patch_stretch && (mode == FILL_LEFT_TO_RIGHT || mode == FILL_RIGHT_TO_LEFT || mode == FILL_TOP_TO_BOTTOM || mode == FILL_BOTTOM_TO_TOP)) {
if (under.is_valid()) {
- draw_nine_patch_stretched(under, FILL_LEFT_TO_RIGHT, 1.0);
+ draw_nine_patch_stretched(under, FILL_LEFT_TO_RIGHT, 1.0, tint_under);
}
if (progress.is_valid()) {
- draw_nine_patch_stretched(progress, mode, get_as_ratio());
+ draw_nine_patch_stretched(progress, mode, get_as_ratio(), tint_progress);
}
if (over.is_valid()) {
- draw_nine_patch_stretched(over, FILL_LEFT_TO_RIGHT, 1.0);
+ draw_nine_patch_stretched(over, FILL_LEFT_TO_RIGHT, 1.0, tint_over);
}
} else {
if (under.is_valid())
- draw_texture(under, Point2());
+ draw_texture(under, Point2(), tint_under);
if (progress.is_valid()) {
Size2 s = progress->get_size();
switch (mode) {
case FILL_LEFT_TO_RIGHT: {
Rect2 region = Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y));
- draw_texture_rect_region(progress, region, region);
+ draw_texture_rect_region(progress, region, region, tint_progress);
} break;
case FILL_RIGHT_TO_LEFT: {
Rect2 region = Rect2(Point2(s.x - s.x * get_as_ratio(), 0), Size2(s.x * get_as_ratio(), s.y));
- draw_texture_rect_region(progress, region, region);
+ draw_texture_rect_region(progress, region, region, tint_progress);
} break;
case FILL_TOP_TO_BOTTOM: {
Rect2 region = Rect2(Point2(), Size2(s.x, s.y * get_as_ratio()));
- draw_texture_rect_region(progress, region, region);
+ draw_texture_rect_region(progress, region, region, tint_progress);
} break;
case FILL_BOTTOM_TO_TOP: {
Rect2 region = Rect2(Point2(0, s.y - s.y * get_as_ratio()), Size2(s.x, s.y * get_as_ratio()));
- draw_texture_rect_region(progress, region, region);
+ draw_texture_rect_region(progress, region, region, tint_progress);
} break;
case FILL_CLOCKWISE:
case FILL_COUNTER_CLOCKWISE: {
float val = get_as_ratio() * rad_max_degrees / 360;
if (val == 1) {
Rect2 region = Rect2(Point2(), s);
- draw_texture_rect_region(progress, region, region);
+ draw_texture_rect_region(progress, region, region, tint_progress);
} else if (val != 0) {
Array pts;
float direction = mode == FILL_CLOCKWISE ? 1 : -1;
@@ -287,7 +338,9 @@ void TextureProgress::_notification(int p_what) {
uvs.push_back(uv);
points.push_back(Point2(uv.x * s.x, uv.y * s.y));
}
- draw_polygon(points, Vector<Color>(), uvs, progress);
+ Vector<Color> colors;
+ colors.push_back(tint_progress);
+ draw_polygon(points, colors, uvs, progress);
}
if (Engine::get_singleton()->is_editor_hint()) {
Point2 p = progress->get_size();
@@ -299,11 +352,11 @@ void TextureProgress::_notification(int p_what) {
}
} break;
default:
- draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)));
+ draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress);
}
}
if (over.is_valid())
- draw_texture(over, Point2());
+ draw_texture(over, Point2(), tint_over);
}
} break;
@@ -365,6 +418,15 @@ void TextureProgress::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fill_mode", "mode"), &TextureProgress::set_fill_mode);
ClassDB::bind_method(D_METHOD("get_fill_mode"), &TextureProgress::get_fill_mode);
+ ClassDB::bind_method(D_METHOD("set_tint_under", "tint"), &TextureProgress::set_tint_under);
+ ClassDB::bind_method(D_METHOD("get_tint_under"), &TextureProgress::get_tint_under);
+
+ ClassDB::bind_method(D_METHOD("set_tint_progress", "tint"), &TextureProgress::set_tint_progress);
+ ClassDB::bind_method(D_METHOD("get_tint_progress"), &TextureProgress::get_tint_progress);
+
+ ClassDB::bind_method(D_METHOD("set_tint_over", "tint"), &TextureProgress::set_tint_over);
+ ClassDB::bind_method(D_METHOD("get_tint_over"), &TextureProgress::get_tint_over);
+
ClassDB::bind_method(D_METHOD("set_radial_initial_angle", "mode"), &TextureProgress::set_radial_initial_angle);
ClassDB::bind_method(D_METHOD("get_radial_initial_angle"), &TextureProgress::get_radial_initial_angle);
@@ -385,6 +447,10 @@ void TextureProgress::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_over_texture", "get_over_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_progress_texture", "get_progress_texture");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise"), "set_fill_mode", "get_fill_mode");
+ ADD_GROUP("Tint", "tint_");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_under", "get_tint_under");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_over", "get_tint_over");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_progress", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_progress", "get_tint_progress");
ADD_GROUP("Radial Fill", "radial_");
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "radial_initial_angle", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_radial_initial_angle", "get_radial_initial_angle");
ADD_PROPERTYNZ(PropertyInfo(Variant::REAL, "radial_fill_degrees", PROPERTY_HINT_RANGE, "0.0,360.0,0.1,slider"), "set_fill_degrees", "get_fill_degrees");
@@ -416,4 +482,6 @@ TextureProgress::TextureProgress() {
stretch_margin[MARGIN_RIGHT] = 0;
stretch_margin[MARGIN_BOTTOM] = 0;
stretch_margin[MARGIN_TOP] = 0;
+
+ tint_under = tint_progress = tint_over = Color(1, 1, 1);
}
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h
index 04096d35e3..34158b5db5 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TEXTURE_PROGRESS_H
#define TEXTURE_PROGRESS_H
@@ -81,6 +82,15 @@ public:
void set_nine_patch_stretch(bool p_stretch);
bool get_nine_patch_stretch() const;
+ void set_tint_under(const Color &p_tint);
+ Color get_tint_under() const;
+
+ void set_tint_progress(const Color &p_tint);
+ Color get_tint_progress() const;
+
+ void set_tint_over(const Color &p_tint);
+ Color get_tint_over() const;
+
Size2 get_minimum_size() const;
TextureProgress();
@@ -92,10 +102,11 @@ private:
Point2 rad_center_off;
bool nine_patch_stretch;
int stretch_margin[4];
+ Color tint_under, tint_progress, tint_over;
Point2 unit_val_to_uv(float val);
Point2 get_relative_center();
- void draw_nine_patch_stretched(const Ref<Texture> &p_texture, FillMode p_mode, double p_ratio);
+ void draw_nine_patch_stretched(const Ref<Texture> &p_texture, FillMode p_mode, double p_ratio, const Color &p_modulate);
};
VARIANT_ENUM_CAST(TextureProgress::FillMode);
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 38f90fe7b5..f4285525f6 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "texture_rect.h"
#include "servers/visual_server.h"
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index 8a2b715488..b684ac816c 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TEXTURE_FRAME_H
#define TEXTURE_FRAME_H
diff --git a/scene/gui/tool_button.cpp b/scene/gui/tool_button.cpp
index 4dfa3d8f37..4220a6b5ce 100644
--- a/scene/gui/tool_button.cpp
+++ b/scene/gui/tool_button.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tool_button.h"
ToolButton::ToolButton() {
diff --git a/scene/gui/tool_button.h b/scene/gui/tool_button.h
index 4c5ea685de..b8be18e560 100644
--- a/scene/gui/tool_button.h
+++ b/scene/gui/tool_button.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TOOL_BUTTON_H
#define TOOL_BUTTON_H
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index ab12d123ba..1d27612766 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,9 +27,11 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tree.h"
#include <limits.h>
+#include "math_funcs.h"
#include "os/input.h"
#include "os/keyboard.h"
#include "os/os.h"
@@ -37,14 +39,18 @@
#include "project_settings.h"
#include "scene/main/viewport.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_node.h"
+#endif
+
void TreeItem::move_to_top() {
- if (!parent || parent->childs == this)
+ if (!parent || parent->children == this)
return; //already on top
TreeItem *prev = get_prev();
prev->next = next;
- next = parent->childs;
- parent->childs = this;
+ next = parent->children;
+ parent->children = this;
}
void TreeItem::move_to_bottom() {
@@ -59,7 +65,7 @@ void TreeItem::move_to_bottom() {
if (prev) {
prev->next = next;
} else {
- parent->childs = next;
+ parent->children = next;
}
last->next = this;
next = NULL;
@@ -362,10 +368,10 @@ TreeItem *TreeItem::get_next() {
TreeItem *TreeItem::get_prev() {
- if (!parent || parent->childs == this)
+ if (!parent || parent->children == this)
return NULL;
- TreeItem *prev = parent->childs;
+ TreeItem *prev = parent->children;
while (prev && prev->next != this)
prev = prev->next;
@@ -379,7 +385,7 @@ TreeItem *TreeItem::get_parent() {
TreeItem *TreeItem::get_children() {
- return childs;
+ return children;
}
TreeItem *TreeItem::get_prev_visible() {
@@ -396,10 +402,10 @@ TreeItem *TreeItem::get_prev_visible() {
} else {
current = prev;
- while (!current->collapsed && current->childs) {
+ while (!current->collapsed && current->children) {
//go to the very end
- current = current->childs;
+ current = current->children;
while (current->next)
current = current->next;
}
@@ -412,9 +418,9 @@ TreeItem *TreeItem::get_next_visible() {
TreeItem *current = this;
- if (!current->collapsed && current->childs) {
+ if (!current->collapsed && current->children) {
- current = current->childs;
+ current = current->children;
} else if (current->next) {
@@ -438,7 +444,7 @@ TreeItem *TreeItem::get_next_visible() {
void TreeItem::remove_child(TreeItem *p_item) {
ERR_FAIL_NULL(p_item);
- TreeItem **c = &childs;
+ TreeItem **c = &children;
while (*c) {
@@ -778,6 +784,10 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collapsed"), "set_collapsed", "is_collapsed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_folding"), "set_disable_folding", "is_folding_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "custom_minimum_height", PROPERTY_HINT_RANGE, "0,1000,1"), "set_custom_minimum_height", "get_custom_minimum_height");
+
BIND_ENUM_CONSTANT(CELL_MODE_STRING);
BIND_ENUM_CONSTANT(CELL_MODE_CHECK);
BIND_ENUM_CONSTANT(CELL_MODE_RANGE);
@@ -792,16 +802,16 @@ void TreeItem::_bind_methods() {
void TreeItem::clear_children() {
- TreeItem *c = childs;
+ TreeItem *c = children;
while (c) {
TreeItem *aux = c;
c = c->get_next();
- aux->parent = 0; // so it wont try to recursively autoremove from me in here
+ aux->parent = 0; // so it won't try to recursively autoremove from me in here
memdelete(aux);
}
- childs = 0;
+ children = 0;
};
TreeItem::TreeItem(Tree *p_tree) {
@@ -813,7 +823,7 @@ TreeItem::TreeItem(Tree *p_tree) {
parent = 0; // parent item
next = 0; // next in list
- childs = 0; //child items
+ children = 0; //child items
}
TreeItem::~TreeItem() {
@@ -910,6 +920,7 @@ int Tree::compute_item_height(TreeItem *p_item) const {
if (p_item == root && hide_root)
return 0;
+ ERR_FAIL_COND_V(cache.font.is_null(), 0);
int height = cache.font->get_height();
for (int i = 0; i < columns.size(); i++) {
@@ -966,9 +977,9 @@ int Tree::get_item_height(TreeItem *p_item) const {
int height = compute_item_height(p_item);
height += cache.vseparation;
- if (!p_item->collapsed) { /* if not collapsed, check the childs */
+ if (!p_item->collapsed) { /* if not collapsed, check the children */
- TreeItem *c = p_item->childs;
+ TreeItem *c = p_item->children;
while (c) {
@@ -983,6 +994,8 @@ int Tree::get_item_height(TreeItem *p_item) const {
void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, const Color &p_color, const Color &p_icon_color) {
+ ERR_FAIL_COND(cache.font.is_null());
+
Rect2i rect = p_rect;
Ref<Font> font = cache.font;
String text = p_cell.text;
@@ -1004,10 +1017,10 @@ void Tree::draw_item_rect(const TreeItem::Cell &p_cell, const Rect2i &p_rect, co
case TreeItem::ALIGN_LEFT:
break; //do none
case TreeItem::ALIGN_CENTER:
- rect.position.x = MAX(0, (rect.size.width - w) / 2);
+ rect.position.x += MAX(0, (rect.size.width - w) / 2);
break; //do none
case TreeItem::ALIGN_RIGHT:
- rect.position.x = MAX(0, (rect.size.width - w));
+ rect.position.x += MAX(0, (rect.size.width - w));
break; //do none
}
@@ -1052,6 +1065,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
//draw separation.
//if (p_item->get_parent()!=root || !hide_root)
+ ERR_FAIL_COND_V(cache.font.is_null(), -1);
Ref<Font> font = cache.font;
int font_ascent = font->get_ascent();
@@ -1372,7 +1386,7 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
}
}
- if (!p_item->disable_folding && !hide_folding && p_item->childs) { //has childs, draw the guide box
+ if (!p_item->disable_folding && !hide_folding && p_item->children) { //has children, draw the guide box
Ref<Texture> arrow;
@@ -1399,9 +1413,9 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
children_pos.y += htotal;
}
- if (!p_item->collapsed) { /* if not collapsed, check the childs */
+ if (!p_item->collapsed) { /* if not collapsed, check the children */
- TreeItem *c = p_item->childs;
+ TreeItem *c = p_item->children;
while (c) {
@@ -1412,18 +1426,39 @@ int Tree::draw_item(const Point2i &p_pos, const Point2 &p_draw_ofs, const Size2
if (c->get_children() != NULL)
root_pos -= Point2i(cache.arrow->get_width(), 0);
+ float line_width = 1.0;
+#ifdef TOOLS_ENABLED
+ line_width *= EDSCALE;
+#endif
+
Point2i parent_pos = Point2i(parent_ofs - cache.arrow->get_width() / 2, p_pos.y + label_h / 2 + cache.arrow->get_height() / 2) - cache.offset + p_draw_ofs;
- VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x, root_pos.y), cache.relationship_line_color);
- VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color);
+
+ if (root_pos.y + line_width >= 0) {
+ VisualServer::get_singleton()->canvas_item_add_line(ci, root_pos, Point2i(parent_pos.x - Math::floor(line_width / 2), root_pos.y), cache.relationship_line_color, line_width);
+ VisualServer::get_singleton()->canvas_item_add_line(ci, Point2i(parent_pos.x, root_pos.y), parent_pos, cache.relationship_line_color, line_width);
+ }
+
+ if (htotal < 0) {
+ return -1;
+ }
}
- int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c);
+ if (htotal >= 0) {
+ int child_h = draw_item(children_pos, p_draw_ofs, p_draw_size, c);
- if (child_h < 0 && cache.draw_relationship_lines == 0)
- return -1; // break, stop drawing, no need to anymore
+ if (child_h < 0) {
+ if (cache.draw_relationship_lines == 0) {
+ return -1; // break, stop drawing, no need to anymore
+ } else {
+ htotal = -1;
+ children_pos.y = cache.offset.y + p_draw_size.height;
+ }
+ } else {
+ htotal += child_h;
+ children_pos.y += child_h;
+ }
+ }
- htotal += child_h;
- children_pos.y += child_h;
c = c->next;
}
}
@@ -1534,7 +1569,7 @@ void Tree::select_single_item(TreeItem *p_selected, TreeItem *p_current, int p_c
*r_in_range = false;
}
- TreeItem *c = p_current->childs;
+ TreeItem *c = p_current->children;
while (c) {
@@ -1600,7 +1635,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
if (!p_item->disable_folding && !hide_folding && (p_pos.x >= x_ofs && p_pos.x < (x_ofs + cache.item_margin))) {
- if (p_item->childs)
+ if (p_item->children)
p_item->set_collapsed(!p_item->is_collapsed());
return -1; //handled!
@@ -1765,7 +1800,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
case TreeItem::CELL_MODE_STRING: {
//nothing in particular
- if (select_mode == SELECT_MULTI && (get_tree()->get_last_event_id() == focus_in_id || !already_cursor)) {
+ if (select_mode == SELECT_MULTI && (get_tree()->get_event_count() == focus_in_id || !already_cursor)) {
bring_up_editor = false;
}
@@ -1853,7 +1888,7 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
} else {
editor_text = String::num(p_item->cells[col].val, Math::step_decimals(p_item->cells[col].step));
- if (select_mode == SELECT_MULTI && get_tree()->get_last_event_id() == focus_in_id)
+ if (select_mode == SELECT_MULTI && get_tree()->get_event_count() == focus_in_id)
bring_up_editor = false;
}
}
@@ -1907,9 +1942,9 @@ int Tree::propagate_mouse_event(const Point2i &p_pos, int x_ofs, int y_ofs, bool
new_pos.y -= item_h;
}
- if (!p_item->collapsed) { /* if not collapsed, check the childs */
+ if (!p_item->collapsed) { /* if not collapsed, check the children */
- TreeItem *c = p_item->childs;
+ TreeItem *c = p_item->children;
while (c) {
@@ -2026,323 +2061,317 @@ void Tree::popup_select(int p_option) {
item_edited(popup_edited_item_col, popup_edited_item);
}
-void Tree::_gui_input(Ref<InputEvent> p_event) {
-
- Ref<InputEventKey> k = p_event;
+void Tree::_go_left() {
+ if (selected_col == 0) {
+ if (selected_item->get_children() != NULL && !selected_item->is_collapsed()) {
+ selected_item->set_collapsed(true);
+ } else {
+ if (columns.size() == 1) { // goto parent with one column
+ TreeItem *parent = selected_item->get_parent();
+ if (selected_item != get_root() && parent && parent->is_selectable(selected_col) && !(hide_root && parent == get_root())) {
+ select_single_item(parent, get_root(), selected_col);
+ }
+ } else if (selected_item->get_prev_visible()) {
+ selected_col = columns.size() - 1;
+ _go_up(); // go to upper column if possible
+ }
+ }
+ } else {
+ if (select_mode == SELECT_MULTI) {
+ selected_col--;
+ emit_signal("cell_selected");
+ } else {
- if (k.is_valid()) {
+ selected_item->select(selected_col - 1);
+ }
+ }
+ update();
+ accept_event();
+ ensure_cursor_is_visible();
+}
- if (!k->is_pressed())
- return;
- if (k->get_command() || (k->get_shift() && k->get_unicode() == 0) || k->get_metakey())
- return;
- if (!root)
+void Tree::_go_right() {
+ if (selected_col == (columns.size() - 1)) {
+ if (selected_item->get_children() != NULL && selected_item->is_collapsed()) {
+ selected_item->set_collapsed(false);
+ } else if (selected_item->get_next_visible()) {
+ selected_item->select(0);
+ _go_down();
return;
+ }
+ } else {
+ if (select_mode == SELECT_MULTI) {
+ selected_col++;
+ emit_signal("cell_selected");
+ } else {
- if (hide_root && !root->get_next_visible())
+ selected_item->select(selected_col + 1);
+ }
+ }
+ update();
+ ensure_cursor_is_visible();
+ accept_event();
+}
+
+void Tree::_go_up() {
+ TreeItem *prev = NULL;
+ if (!selected_item) {
+ prev = get_last_item();
+ selected_col = 0;
+ } else {
+
+ prev = selected_item->get_prev_visible();
+ if (last_keypress != 0) {
+ //incr search next
+ int col;
+ prev = _search_item_text(prev, incr_search, &col, true, true);
+ if (!prev) {
+ accept_event();
+ return;
+ }
+ }
+ }
+
+ if (select_mode == SELECT_MULTI) {
+
+ if (!prev)
return;
+ selected_item = prev;
+ emit_signal("cell_selected");
+ update();
+ } else {
- switch (k->get_scancode()) {
-#define EXIT_BREAK \
- { \
- if (!cursor_can_exit_tree) accept_event(); \
- break; \
+ int col = selected_col < 0 ? 0 : selected_col;
+ while (prev && !prev->cells[col].selectable)
+ prev = prev->get_prev_visible();
+ if (!prev)
+ return; // do nothing..
+ prev->select(col);
}
- case KEY_RIGHT: {
- bool dobreak = true;
- //TreeItem *next = NULL;
- if (!selected_item)
- break;
- if (select_mode == SELECT_ROW) {
- EXIT_BREAK;
- }
- if (selected_col > (columns.size() - 1)) {
- EXIT_BREAK;
- }
- if (k->get_alt()) {
- selected_item->set_collapsed(false);
- TreeItem *next = selected_item->get_children();
- while (next && next != selected_item->next) {
- next->set_collapsed(false);
- next = next->get_next_visible();
- }
- } else if (selected_col == (columns.size() - 1)) {
- if (selected_item->get_children() != NULL && selected_item->is_collapsed()) {
- selected_item->set_collapsed(false);
- } else {
- selected_col = 0;
- dobreak = false; // fall through to key_down
- }
- } else {
- if (select_mode == SELECT_MULTI) {
- selected_col++;
- emit_signal("cell_selected");
- } else {
+ ensure_cursor_is_visible();
+ accept_event();
+}
- selected_item->select(selected_col + 1);
- }
- }
- update();
- ensure_cursor_is_visible();
+void Tree::_go_down() {
+ TreeItem *next = NULL;
+ if (!selected_item) {
+
+ next = hide_root ? root->get_next_visible() : root;
+ selected_item = 0;
+ } else {
+
+ next = selected_item->get_next_visible();
+
+ if (last_keypress != 0) {
+ //incr search next
+ int col;
+ next = _search_item_text(next, incr_search, &col, true);
+ if (!next) {
accept_event();
- if (dobreak) {
- break;
- }
+ return;
}
- case KEY_DOWN: {
+ }
+ }
- TreeItem *next = NULL;
- if (!selected_item) {
+ if (select_mode == SELECT_MULTI) {
- next = hide_root ? root->get_next_visible() : root;
- selected_item = 0;
- } else {
+ if (!next) {
+ return;
+ }
- next = selected_item->get_next_visible();
+ selected_item = next;
+ emit_signal("cell_selected");
+ update();
+ } else {
- //if (diff < uint64_t(GLOBAL_DEF("gui/incr_search_max_interval_msec",2000))) {
- if (last_keypress != 0) {
- //incr search next
- int col;
- next = _search_item_text(next, incr_search, &col, true);
- if (!next) {
- accept_event();
- return;
- }
- }
- }
+ int col = selected_col < 0 ? 0 : selected_col;
- if (select_mode == SELECT_MULTI) {
+ while (next && !next->cells[col].selectable)
+ next = next->get_next_visible();
+ if (!next) {
+ return; // do nothing..
+ }
+ next->select(col);
+ }
- if (!next)
- EXIT_BREAK;
+ ensure_cursor_is_visible();
+ accept_event();
+}
- selected_item = next;
- emit_signal("cell_selected");
- update();
- } else {
+void Tree::_gui_input(Ref<InputEvent> p_event) {
- int col = selected_col < 0 ? 0 : selected_col;
+ Ref<InputEventKey> k = p_event;
- while (next && !next->cells[col].selectable)
- next = next->get_next_visible();
- if (!next)
- EXIT_BREAK; // do nothing..
- next->select(col);
- }
+ if (p_event->is_action("ui_right") && p_event->is_pressed()) {
- ensure_cursor_is_visible();
- accept_event();
+ if (!cursor_can_exit_tree) accept_event();
- } break;
- case KEY_LEFT: {
- bool dobreak = true;
+ if (!selected_item || select_mode == SELECT_ROW || selected_col > (columns.size() - 1)) {
+ return;
+ }
+ if (k.is_valid() && k->get_alt()) {
+ selected_item->set_collapsed(false);
+ TreeItem *next = selected_item->get_children();
+ while (next && next != selected_item->next) {
+ next->set_collapsed(false);
+ next = next->get_next_visible();
+ }
+ } else {
+ _go_right();
+ }
+ } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
- //TreeItem *next = NULL;
- if (!selected_item)
- break;
- if (select_mode == SELECT_ROW) {
- EXIT_BREAK;
- }
- if (selected_col < 0) {
- EXIT_BREAK;
- }
- if (k->get_alt()) {
- selected_item->set_collapsed(true);
- TreeItem *next = selected_item->get_children();
- while (next && next != selected_item->next) {
- next->set_collapsed(true);
- next = next->get_next_visible();
- }
- } else if (selected_col == 0) {
- if (selected_item->get_children() != NULL && !selected_item->is_collapsed()) {
- selected_item->set_collapsed(true);
- } else {
- if (columns.size() == 1) { // goto parent with one column
- TreeItem *parent = selected_item->get_parent();
- if (selected_item != get_root() && parent && parent->is_selectable(selected_col) && !(hide_root && parent == get_root())) {
- select_single_item(parent, get_root(), selected_col);
- }
- } else {
- selected_col = columns.size() - 1;
- dobreak = false; // fall through to key_up
- }
- }
- } else {
- if (select_mode == SELECT_MULTI) {
- selected_col--;
- emit_signal("cell_selected");
- } else {
+ if (!cursor_can_exit_tree) accept_event();
- selected_item->select(selected_col - 1);
- }
- }
- update();
- accept_event();
- ensure_cursor_is_visible();
+ if (!selected_item || select_mode == SELECT_ROW || selected_col < 0) {
+ return;
+ }
- if (dobreak) {
- break;
- }
+ if (k.is_valid() && k->get_alt()) {
+ selected_item->set_collapsed(true);
+ TreeItem *next = selected_item->get_children();
+ while (next && next != selected_item->next) {
+ next->set_collapsed(true);
+ next = next->get_next_visible();
}
- case KEY_UP: {
+ } else {
+ _go_left();
+ }
- TreeItem *prev = NULL;
- if (!selected_item) {
- prev = get_last_item();
- selected_col = 0;
- } else {
+ } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
- prev = selected_item->get_prev_visible();
- if (last_keypress != 0) {
- //incr search next
- int col;
- prev = _search_item_text(prev, incr_search, &col, true, true);
- if (!prev) {
- accept_event();
- return;
- }
- }
- }
+ if (!cursor_can_exit_tree) accept_event();
- if (select_mode == SELECT_MULTI) {
+ _go_up();
- if (!prev)
- break;
- selected_item = prev;
- emit_signal("cell_selected");
- update();
- } else {
+ } else if (p_event->is_action("ui_down") && p_event->is_pressed()) {
- int col = selected_col < 0 ? 0 : selected_col;
- while (prev && !prev->cells[col].selectable)
- prev = prev->get_prev_visible();
- if (!prev)
- break; // do nothing..
- prev->select(col);
- }
+ if (!cursor_can_exit_tree) accept_event();
- ensure_cursor_is_visible();
- accept_event();
+ _go_down();
- } break;
- case KEY_PAGEDOWN: {
+ } else if (p_event->is_action("ui_page_down") && p_event->is_pressed()) {
- TreeItem *next = NULL;
- if (!selected_item)
- break;
- next = selected_item;
+ if (!cursor_can_exit_tree) accept_event();
- for (int i = 0; i < 10; i++) {
+ TreeItem *next = NULL;
+ if (!selected_item)
+ return;
+ next = selected_item;
- TreeItem *_n = next->get_next_visible();
- if (_n) {
- next = _n;
- } else {
+ for (int i = 0; i < 10; i++) {
- break;
- }
- }
- if (next == selected_item)
- break;
+ TreeItem *_n = next->get_next_visible();
+ if (_n) {
+ next = _n;
+ } else {
- if (select_mode == SELECT_MULTI) {
+ return;
+ }
+ }
+ if (next == selected_item)
+ return;
- selected_item = next;
- emit_signal("cell_selected");
- update();
- } else {
+ if (select_mode == SELECT_MULTI) {
- while (next && !next->cells[selected_col].selectable)
- next = next->get_next_visible();
- if (!next)
- EXIT_BREAK; // do nothing..
- next->select(selected_col);
- }
+ selected_item = next;
+ emit_signal("cell_selected");
+ update();
+ } else {
- ensure_cursor_is_visible();
- } break;
- case KEY_PAGEUP: {
+ while (next && !next->cells[selected_col].selectable)
+ next = next->get_next_visible();
+ if (!next) {
+ return; // do nothing..
+ }
+ next->select(selected_col);
+ }
- TreeItem *prev = NULL;
- if (!selected_item)
- break;
- prev = selected_item;
+ ensure_cursor_is_visible();
+ } else if (p_event->is_action("ui_page_up") && p_event->is_pressed()) {
- for (int i = 0; i < 10; i++) {
+ if (!cursor_can_exit_tree) accept_event();
- TreeItem *_n = prev->get_prev_visible();
- if (_n) {
- prev = _n;
- } else {
+ TreeItem *prev = NULL;
+ if (!selected_item)
+ return;
+ prev = selected_item;
- break;
- }
- }
- if (prev == selected_item)
- break;
+ for (int i = 0; i < 10; i++) {
- if (select_mode == SELECT_MULTI) {
+ TreeItem *_n = prev->get_prev_visible();
+ if (_n) {
+ prev = _n;
+ } else {
- selected_item = prev;
- emit_signal("cell_selected");
- update();
- } else {
+ return;
+ }
+ }
+ if (prev == selected_item)
+ return;
- while (prev && !prev->cells[selected_col].selectable)
- prev = prev->get_prev_visible();
- if (!prev)
- EXIT_BREAK; // do nothing..
- prev->select(selected_col);
- }
+ if (select_mode == SELECT_MULTI) {
- ensure_cursor_is_visible();
+ selected_item = prev;
+ emit_signal("cell_selected");
+ update();
+ } else {
- } break;
- case KEY_F2:
- case KEY_ENTER:
- case KEY_KP_ENTER: {
-
- if (selected_item) {
- //bring up editor if possible
- if (!edit_selected()) {
- emit_signal("item_activated");
- incr_search.clear();
- }
- }
- accept_event();
+ while (prev && !prev->cells[selected_col].selectable)
+ prev = prev->get_prev_visible();
+ if (!prev) {
+ return; // do nothing..
+ }
+ prev->select(selected_col);
+ }
+ ensure_cursor_is_visible();
+ } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
- } break;
- case KEY_SPACE: {
- if (select_mode == SELECT_MULTI) {
- if (!selected_item)
- break;
- if (selected_item->is_selected(selected_col)) {
- selected_item->deselect(selected_col);
- emit_signal("multi_selected", selected_item, selected_col, false);
- } else if (selected_item->is_selectable(selected_col)) {
- selected_item->select(selected_col);
- emit_signal("multi_selected", selected_item, selected_col, true);
- }
- }
- accept_event();
+ if (selected_item) {
+ //bring up editor if possible
+ if (!edit_selected()) {
+ emit_signal("item_activated");
+ incr_search.clear();
+ }
+ }
+ accept_event();
+ } else if (p_event->is_action("ui_select") && p_event->is_pressed()) {
- } break;
- default: {
+ if (select_mode == SELECT_MULTI) {
+ if (!selected_item)
+ return;
+ if (selected_item->is_selected(selected_col)) {
+ selected_item->deselect(selected_col);
+ emit_signal("multi_selected", selected_item, selected_col, false);
+ } else if (selected_item->is_selectable(selected_col)) {
+ selected_item->select(selected_col);
+ emit_signal("multi_selected", selected_item, selected_col, true);
+ }
+ }
+ accept_event();
+ }
- if (k->get_unicode() > 0) {
+ if (k.is_valid()) { // Incremental search
- _do_incr_search(String::chr(k->get_unicode()));
- accept_event();
+ if (!k->is_pressed())
+ return;
+ if (k->get_command() || (k->get_shift() && k->get_unicode() == 0) || k->get_metakey())
+ return;
+ if (!root)
+ return;
- return;
- } else {
- if (k->get_scancode() != KEY_SHIFT)
- last_keypress = 0;
- }
- } break;
+ if (hide_root && !root->get_next_visible())
+ return;
+
+ if (k->get_unicode() > 0) {
+
+ _do_incr_search(String::chr(k->get_unicode()));
+ accept_event();
+ return;
+ } else {
+ if (k->get_scancode() != KEY_SHIFT)
last_keypress = 0;
}
}
@@ -2351,7 +2380,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (mm.is_valid()) {
- if (cache.font.is_null()) // avoid a strange case that may fuckup stuff
+ if (cache.font.is_null()) // avoid a strange case that may corrupt stuff
update_cache();
Ref<StyleBox> bg = cache.bg;
@@ -2450,7 +2479,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
- if (cache.font.is_null()) // avoid a strange case that may fuckup stuff
+ if (cache.font.is_null()) // avoid a strange case that may corrupt stuff
update_cache();
if (!b->is_pressed()) {
@@ -2516,7 +2545,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
if (drag_speed == 0) {
drag_touching_deaccel = false;
drag_touching = false;
- set_physics_process(false);
+ set_physics_process_internal(false);
} else {
drag_touching_deaccel = true;
@@ -2582,7 +2611,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
break;
if (drag_touching) {
- set_physics_process(false);
+ set_physics_process_internal(false);
drag_touching_deaccel = false;
drag_touching = false;
drag_speed = 0;
@@ -2597,7 +2626,7 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
drag_touching_deaccel = false;
if (drag_touching) {
- set_physics_process(true);
+ set_physics_process_internal(true);
}
if (b->get_button_index() == BUTTON_LEFT) {
@@ -2769,6 +2798,7 @@ void Tree::update_scrollbars() {
int Tree::_get_title_button_height() const {
+ ERR_FAIL_COND_V(cache.font.is_null() || cache.title_button.is_null(), 0);
return show_column_titles ? cache.font->get_height() + cache.title_button->get_minimum_size().height : 0;
}
@@ -2776,7 +2806,7 @@ void Tree::_notification(int p_what) {
if (p_what == NOTIFICATION_FOCUS_ENTER) {
- focus_in_id = get_tree()->get_last_event_id();
+ focus_in_id = get_tree()->get_event_count();
}
if (p_what == NOTIFICATION_MOUSE_EXIT) {
@@ -2799,7 +2829,7 @@ void Tree::_notification(int p_what) {
drop_mode_flags = 0;
scrolling = false;
- set_physics_process(false);
+ set_physics_process_internal(false);
update();
}
if (p_what == NOTIFICATION_DRAG_BEGIN) {
@@ -2807,10 +2837,10 @@ void Tree::_notification(int p_what) {
single_select_defer = NULL;
if (cache.scroll_speed > 0 && get_rect().has_point(get_viewport()->get_mouse_position() - get_global_position())) {
scrolling = true;
- set_physics_process(true);
+ set_physics_process_internal(true);
}
}
- if (p_what == NOTIFICATION_PHYSICS_PROCESS) {
+ if (p_what == NOTIFICATION_INTERNAL_PHYSICS_PROCESS) {
if (drag_touching) {
@@ -2823,7 +2853,7 @@ void Tree::_notification(int p_what) {
if (pos < 0) {
pos = 0;
turnoff = true;
- set_physics_process(false);
+ set_physics_process_internal(false);
drag_touching = false;
drag_touching_deaccel = false;
}
@@ -2843,7 +2873,7 @@ void Tree::_notification(int p_what) {
drag_speed = sgn * val;
if (turnoff) {
- set_physics_process(false);
+ set_physics_process_internal(false);
drag_touching = false;
drag_touching_deaccel = false;
}
@@ -2940,43 +2970,51 @@ Size2 Tree::get_minimum_size() const {
return Size2(1, 1);
}
-TreeItem *Tree::create_item(TreeItem *p_parent) {
+TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
ERR_FAIL_COND_V(blocked > 0, NULL);
- TreeItem *ti = memnew(TreeItem(this));
-
- ERR_FAIL_COND_V(!ti, NULL);
- ti->cells.resize(columns.size());
+ TreeItem *ti = NULL;
if (p_parent) {
- /* Always append at the end */
+ // Append or insert a new item to the given parent.
+ ti = memnew(TreeItem(this));
+ ERR_FAIL_COND_V(!ti, NULL);
+ ti->cells.resize(columns.size());
- TreeItem *last = 0;
- TreeItem *c = p_parent->childs;
+ TreeItem *prev = NULL;
+ TreeItem *c = p_parent->children;
+ int idx = 0;
while (c) {
-
- last = c;
+ if (idx++ == p_idx) {
+ ti->next = c;
+ break;
+ }
+ prev = c;
c = c->next;
}
- if (last) {
-
- last->next = ti;
- } else {
-
- p_parent->childs = ti;
- }
+ if (prev)
+ prev->next = ti;
+ else
+ p_parent->children = ti;
ti->parent = p_parent;
} else {
- if (root)
- ti->childs = root;
+ if (!root) {
+ // No root exists, make the given item the new root.
+ ti = memnew(TreeItem(this));
+ ERR_FAIL_COND_V(!ti, NULL);
+ ti->cells.resize(columns.size());
- root = ti;
+ root = ti;
+ } else {
+ // Root exists, append or insert to root.
+ ti = create_item(root, p_idx);
+ }
}
return ti;
@@ -2994,8 +3032,8 @@ TreeItem *Tree::get_last_item() {
if (last->next)
last = last->next;
- else if (last->childs)
- last = last->childs;
+ else if (last->children)
+ last = last->children;
else
break;
}
@@ -3028,6 +3066,7 @@ void Tree::item_selected(int p_column, TreeItem *p_item) {
p_item->cells[p_column].selected = true;
//emit_signal("multi_selected",p_item,p_column,true); - NO this is for TreeItem::select
+ selected_col = p_column;
} else {
select_single_item(p_item, root, p_column);
@@ -3048,12 +3087,19 @@ void Tree::set_select_mode(SelectMode p_mode) {
select_mode = p_mode;
}
+Tree::SelectMode Tree::get_select_mode() const {
+
+ return select_mode;
+}
+
void Tree::deselect_all() {
TreeItem *item = get_next_selected(get_root());
while (item) {
item->deselect(selected_col);
+ TreeItem *prev_item = item;
item = get_next_selected(get_root());
+ ERR_FAIL_COND(item == prev_item);
}
selected_item = NULL;
@@ -3101,6 +3147,11 @@ void Tree::set_hide_root(bool p_enabled) {
update();
}
+bool Tree::is_root_hidden() const {
+
+ return hide_root;
+}
+
void Tree::set_column_min_width(int p_column, int p_min_width) {
ERR_FAIL_INDEX(p_column, columns.size());
@@ -3153,9 +3204,9 @@ TreeItem *Tree::get_next_selected(TreeItem *p_item) {
p_item = root;
} else {
- if (p_item->childs) {
+ if (p_item->children) {
- p_item = p_item->childs;
+ p_item = p_item->children;
} else if (p_item->next) {
@@ -3270,9 +3321,9 @@ int Tree::get_item_offset(TreeItem *p_item) const {
ofs += compute_item_height(it) + cache.vseparation;
- if (it->childs && !it->collapsed) {
+ if (it->children && !it->collapsed) {
- it = it->childs;
+ it = it->children;
} else if (it->next) {
@@ -3493,7 +3544,7 @@ TreeItem *Tree::_find_item_at_pos(TreeItem *p_item, const Point2 &p_pos, int &r_
}
if (p_item->is_collapsed())
- return NULL; // do not try childs, it's collapsed
+ return NULL; // do not try children, it's collapsed
TreeItem *n = p_item->get_children();
while (n) {
@@ -3713,7 +3764,7 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("_scroll_moved"), &Tree::_scroll_moved);
ClassDB::bind_method(D_METHOD("clear"), &Tree::clear);
- ClassDB::bind_method(D_METHOD("create_item", "parent"), &Tree::_create_item, DEFVAL(Variant()));
+ ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::_create_item, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root);
ClassDB::bind_method(D_METHOD("set_column_min_width", "column", "min_width"), &Tree::set_column_min_width);
@@ -3721,11 +3772,13 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_column_width", "column"), &Tree::get_column_width);
ClassDB::bind_method(D_METHOD("set_hide_root", "enable"), &Tree::set_hide_root);
+ ClassDB::bind_method(D_METHOD("is_root_hidden"), &Tree::is_root_hidden);
ClassDB::bind_method(D_METHOD("get_next_selected", "from"), &Tree::_get_next_selected);
ClassDB::bind_method(D_METHOD("get_selected"), &Tree::get_selected);
ClassDB::bind_method(D_METHOD("get_selected_column"), &Tree::get_selected_column);
ClassDB::bind_method(D_METHOD("get_pressed_button"), &Tree::get_pressed_button);
ClassDB::bind_method(D_METHOD("set_select_mode", "mode"), &Tree::set_select_mode);
+ ClassDB::bind_method(D_METHOD("get_select_mode"), &Tree::get_select_mode);
ClassDB::bind_method(D_METHOD("set_columns", "amount"), &Tree::set_columns);
ClassDB::bind_method(D_METHOD("get_columns"), &Tree::get_columns);
@@ -3759,6 +3812,14 @@ void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_allow_reselect", "allow"), &Tree::set_allow_reselect);
ClassDB::bind_method(D_METHOD("get_allow_reselect"), &Tree::get_allow_reselect);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "columns"), "set_columns", "get_columns");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_folding"), "set_hide_folding", "is_folding_hidden");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_root"), "set_hide_root", "is_root_hidden");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "drop_mode_flags", PROPERTY_HINT_FLAGS, "On Item,In between"), "set_drop_mode_flags", "get_drop_mode_flags");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Row,Multi"), "set_select_mode", "get_select_mode");
+
ADD_SIGNAL(MethodInfo("item_selected"));
ADD_SIGNAL(MethodInfo("cell_selected"));
ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::OBJECT, "item"), PropertyInfo(Variant::INT, "column"), PropertyInfo(Variant::BOOL, "selected")));
@@ -3846,6 +3907,8 @@ Tree::Tree() {
cache.click_id = -1;
cache.click_item = NULL;
cache.click_column = 0;
+ cache.hover_cell = -1;
+ cache.hover_index = -1;
last_keypress = 0;
focus_in_id = 0;
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index 112de3165f..5af66c5faa 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TREE_H
#define TREE_H
@@ -143,13 +144,13 @@ private:
Vector<Cell> cells;
- bool collapsed; // wont show childs
+ bool collapsed; // won't show children
bool disable_folding;
int custom_min_height;
TreeItem *parent; // parent item
TreeItem *next; // next in list
- TreeItem *childs; //child items
+ TreeItem *children; //child items
Tree *tree; //tree (for reference)
TreeItem(Tree *p_tree);
@@ -359,7 +360,7 @@ private:
LineEdit *text_editor;
HSlider *value_editor;
bool updating_value_editor;
- uint32_t focus_in_id;
+ int64_t focus_in_id;
PopupMenu *popup_menu;
Vector<ColumnInfo> columns;
@@ -506,13 +507,17 @@ private:
ValueEvaluator *evaluator;
int _count_selected_items(TreeItem *p_from) const;
+ void _go_left();
+ void _go_right();
+ void _go_down();
+ void _go_up();
protected:
static void _bind_methods();
//bind helpers
- Object *_create_item(Object *p_parent) {
- return create_item(Object::cast_to<TreeItem>(p_parent));
+ Object *_create_item(Object *p_parent, int p_idx = -1) {
+ return create_item(Object::cast_to<TreeItem>(p_parent), p_idx);
}
TreeItem *_get_next_selected(Object *p_item) {
@@ -532,7 +537,7 @@ public:
void clear();
- TreeItem *create_item(TreeItem *p_parent = 0);
+ TreeItem *create_item(TreeItem *p_parent = 0, int p_idx = -1);
TreeItem *get_root();
TreeItem *get_last_item();
@@ -541,11 +546,13 @@ public:
int get_column_width(int p_column) const;
void set_hide_root(bool p_enabled);
+ bool is_root_hidden() const;
TreeItem *get_next_selected(TreeItem *p_item);
TreeItem *get_selected() const;
int get_selected_column() const;
int get_pressed_button() const;
void set_select_mode(SelectMode p_mode);
+ SelectMode get_select_mode() const;
void deselect_all();
bool is_anything_selected();
diff --git a/scene/gui/video_player.cpp b/scene/gui/video_player.cpp
index 8f567f9796..88e1847533 100644
--- a/scene/gui/video_player.cpp
+++ b/scene/gui/video_player.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,7 +27,9 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "video_player.h"
+#include "scene/scene_string_names.h"
#include "os/os.h"
#include "servers/audio_server.h"
@@ -37,11 +39,6 @@ int VideoPlayer::sp_get_channel_count() const {
return playback->get_channels();
}
-void VideoPlayer::sp_set_mix_rate(int p_rate) {
-
- server_mix_rate = p_rate;
-}
-
bool VideoPlayer::mix(AudioFrame *p_buffer, int p_frames) {
// Check the amount resampler can really handle.
@@ -163,11 +160,7 @@ void VideoPlayer::_notification(int p_notification) {
bus_index = AudioServer::get_singleton()->thread_find_bus_index(bus);
- if (stream.is_null())
- return;
- if (paused)
- return;
- if (!playback->is_playing())
+ if (stream.is_null() || paused || !playback->is_playing())
return;
double audio_time = USEC_TO_SEC(OS::get_singleton()->get_ticks_usec());
@@ -178,7 +171,11 @@ void VideoPlayer::_notification(int p_notification) {
if (delta == 0)
return;
- playback->update(delta);
+ playback->update(delta); // playback->is_playing() returns false in the last video frame
+
+ if (!playback->is_playing()) {
+ emit_signal(SceneStringNames::get_singleton()->finished);
+ }
} break;
@@ -240,7 +237,7 @@ void VideoPlayer::set_stream(const Ref<VideoStream> &p_stream) {
AudioServer::get_singleton()->lock();
if (channels > 0)
- resampler.setup(channels, playback->get_mix_rate(), server_mix_rate, buffering_ms, 0);
+ resampler.setup(channels, playback->get_mix_rate(), AudioServer::get_singleton()->get_mix_rate(), buffering_ms, 0);
else
resampler.clear();
AudioServer::get_singleton()->unlock();
@@ -471,13 +468,19 @@ void VideoPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_video_texture"), &VideoPlayer::get_video_texture);
+ ADD_SIGNAL(MethodInfo("finished"));
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "audio_track", PROPERTY_HINT_RANGE, "0,128,1"), "set_audio_track", "get_audio_track");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "VideoStream"), "set_stream", "get_stream");
//ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), "set_loop", "has_loop") ;
ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume_db", PROPERTY_HINT_RANGE, "-80,24,0.01"), "set_volume_db", "get_volume_db");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "volume", PROPERTY_HINT_EXP_RANGE, "0,15,0.01", 0), "set_volume", "get_volume");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "has_autoplay");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_paused", "is_paused");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand"), "set_expand", "has_expand");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "buffering_msec", PROPERTY_HINT_RANGE, "10,1000"), "set_buffering_msec", "get_buffering_msec");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "stream_position", PROPERTY_HINT_RANGE, "0,1280000,0.1", 0), "set_stream_position", "get_stream_position");
+
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus");
}
@@ -493,7 +496,6 @@ VideoPlayer::VideoPlayer() {
bus_index = 0;
buffering_ms = 500;
- server_mix_rate = 44100;
// internal_stream.player=this;
// stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
diff --git a/scene/gui/video_player.h b/scene/gui/video_player.h
index 74e2f14e58..5c379b5620 100644
--- a/scene/gui/video_player.h
+++ b/scene/gui/video_player.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VIDEO_PLAYER_H
#define VIDEO_PLAYER_H
@@ -49,7 +50,6 @@ class VideoPlayer : public Control {
Ref<VideoStream> stream;
int sp_get_channel_count() const;
- void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
bool mix(AudioFrame *p_buffer, int p_frames);
RID stream_rid;
@@ -68,7 +68,6 @@ class VideoPlayer : public Control {
bool expand;
bool loops;
int buffering_ms;
- int server_mix_rate;
int audio_track;
int bus_index;
diff --git a/scene/gui/viewport_container.cpp b/scene/gui/viewport_container.cpp
index 9244d8de2f..ac5e6020eb 100644
--- a/scene/gui/viewport_container.cpp
+++ b/scene/gui/viewport_container.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,8 +27,10 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "viewport_container.h"
+#include "core/engine.h"
#include "scene/main/viewport.h"
Size2 ViewportContainer::get_minimum_size() const {
@@ -138,8 +140,34 @@ void ViewportContainer::_notification(int p_what) {
}
}
+void ViewportContainer::_input(const Ref<InputEvent> &p_event) {
+
+ if (Engine::get_singleton()->is_editor_hint())
+ return;
+
+ Transform2D xform = get_global_transform();
+
+ if (stretch) {
+ Transform2D scale_xf;
+ scale_xf.scale(Vector2(shrink, shrink));
+ xform *= scale_xf;
+ }
+
+ Ref<InputEvent> ev = p_event->xformed_by(xform.affine_inverse());
+
+ for (int i = 0; i < get_child_count(); i++) {
+
+ Viewport *c = Object::cast_to<Viewport>(get_child(i));
+ if (!c || c->is_input_disabled())
+ continue;
+
+ c->input(ev);
+ }
+}
+
void ViewportContainer::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_input", "event"), &ViewportContainer::_input);
ClassDB::bind_method(D_METHOD("set_stretch", "enable"), &ViewportContainer::set_stretch);
ClassDB::bind_method(D_METHOD("is_stretch_enabled"), &ViewportContainer::is_stretch_enabled);
@@ -154,4 +182,5 @@ ViewportContainer::ViewportContainer() {
stretch = false;
shrink = 1;
+ set_process_input(true);
}
diff --git a/scene/gui/viewport_container.h b/scene/gui/viewport_container.h
index ebf5869ed9..45c4cd03a1 100644
--- a/scene/gui/viewport_container.h
+++ b/scene/gui/viewport_container.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VIEWPORTCONTAINER_H
#define VIEWPORTCONTAINER_H
@@ -47,6 +48,7 @@ public:
void set_stretch(bool p_enable);
bool is_stretch_enabled() const;
+ void _input(const Ref<InputEvent> &p_event);
void set_stretch_shrink(int p_shrink);
int get_stretch_shrink() const;
diff --git a/scene/main/canvas_layer.cpp b/scene/main/canvas_layer.cpp
index 5a3814ef35..8414210952 100644
--- a/scene/main/canvas_layer.cpp
+++ b/scene/main/canvas_layer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "canvas_layer.h"
#include "viewport.h"
@@ -34,7 +35,7 @@ void CanvasLayer::set_layer(int p_xform) {
layer = p_xform;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas->get_canvas(), layer);
+ VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer);
}
int CanvasLayer::get_layer() const {
@@ -47,7 +48,7 @@ void CanvasLayer::set_transform(const Transform2D &p_xform) {
transform = p_xform;
locrotscale_dirty = true;
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform);
+ VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
Transform2D CanvasLayer::get_transform() const {
@@ -60,7 +61,7 @@ void CanvasLayer::_update_xform() {
transform.set_rotation_and_scale(rot, scale);
transform.set_origin(ofs);
if (viewport.is_valid())
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform);
+ VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
void CanvasLayer::_update_locrotscale() {
@@ -132,11 +133,6 @@ Vector2 CanvasLayer::get_scale() const {
return scale;
}
-Ref<World2D> CanvasLayer::get_world_2d() const {
-
- return canvas;
-}
-
void CanvasLayer::_notification(int p_what) {
switch (p_what) {
@@ -152,14 +148,14 @@ void CanvasLayer::_notification(int p_what) {
ERR_FAIL_COND(!vp);
viewport = vp->get_viewport_rid();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas->get_canvas());
- VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas->get_canvas(), layer);
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform);
+ VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer);
+ VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
} break;
case NOTIFICATION_EXIT_TREE: {
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas->get_canvas());
+ VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
} break;
@@ -183,7 +179,7 @@ RID CanvasLayer::get_viewport() const {
void CanvasLayer::set_custom_viewport(Node *p_viewport) {
ERR_FAIL_NULL(p_viewport);
if (is_inside_tree()) {
- VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas->get_canvas());
+ VisualServer::get_singleton()->viewport_remove_canvas(viewport, canvas);
viewport = RID();
}
@@ -204,9 +200,9 @@ void CanvasLayer::set_custom_viewport(Node *p_viewport) {
viewport = vp->get_viewport_rid();
- VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas->get_canvas());
- VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas->get_canvas(), layer);
- VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas->get_canvas(), transform);
+ VisualServer::get_singleton()->viewport_attach_canvas(viewport, canvas);
+ VisualServer::get_singleton()->viewport_set_canvas_layer(viewport, canvas, layer);
+ VisualServer::get_singleton()->viewport_set_canvas_transform(viewport, canvas, transform);
}
}
@@ -224,6 +220,10 @@ int CanvasLayer::get_sort_index() {
return sort_index++;
}
+RID CanvasLayer::get_canvas() const {
+
+ return canvas;
+}
void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_layer", "layer"), &CanvasLayer::set_layer);
@@ -247,14 +247,17 @@ void CanvasLayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_custom_viewport", "viewport"), &CanvasLayer::set_custom_viewport);
ClassDB::bind_method(D_METHOD("get_custom_viewport"), &CanvasLayer::get_custom_viewport);
- ClassDB::bind_method(D_METHOD("get_world_2d"), &CanvasLayer::get_world_2d);
+ ClassDB::bind_method(D_METHOD("get_canvas"), &CanvasLayer::get_canvas);
//ClassDB::bind_method(D_METHOD("get_viewport"),&CanvasLayer::get_viewport);
ADD_PROPERTY(PropertyInfo(Variant::INT, "layer", PROPERTY_HINT_RANGE, "-128,128,1"), "set_layer", "get_layer");
//ADD_PROPERTY( PropertyInfo(Variant::MATRIX32,"transform",PROPERTY_HINT_RANGE),"set_transform","get_transform") ;
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "offset"), "set_offset", "get_offset");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation"), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation_degrees", PROPERTY_HINT_RANGE, "-1440,1440,0.1", PROPERTY_USAGE_EDITOR), "set_rotation_degrees", "get_rotation_degrees");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_rotation", "get_rotation");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "scale"), "set_scale", "get_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "transform"), "set_transform", "get_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "custom_viewport", PROPERTY_HINT_RESOURCE_TYPE, "Viewport", 0), "set_custom_viewport", "get_custom_viewport");
}
CanvasLayer::CanvasLayer() {
@@ -264,8 +267,13 @@ CanvasLayer::CanvasLayer() {
rot = 0;
locrotscale_dirty = false;
layer = 1;
- canvas = Ref<World2D>(memnew(World2D));
+ canvas = VS::get_singleton()->canvas_create();
custom_viewport = NULL;
custom_viewport_id = 0;
sort_index = 0;
}
+
+CanvasLayer::~CanvasLayer() {
+
+ VS::get_singleton()->free(canvas);
+}
diff --git a/scene/main/canvas_layer.h b/scene/main/canvas_layer.h
index db2c8e1273..aae23fbb12 100644
--- a/scene/main/canvas_layer.h
+++ b/scene/main/canvas_layer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CANVAS_LAYER_H
#define CANVAS_LAYER_H
@@ -44,7 +45,7 @@ class CanvasLayer : public Node {
real_t rot;
int layer;
Transform2D transform;
- Ref<World2D> canvas;
+ RID canvas;
ObjectID custom_viewport_id; // to check validity
Viewport *custom_viewport;
@@ -80,8 +81,6 @@ public:
void set_scale(const Size2 &p_scale);
Size2 get_scale() const;
- Ref<World2D> get_world_2d() const;
-
Size2 get_viewport_size() const;
RID get_viewport() const;
@@ -92,7 +91,10 @@ public:
void reset_sort_index();
int get_sort_index();
+ RID get_canvas() const;
+
CanvasLayer();
+ ~CanvasLayer();
};
#endif // CANVAS_LAYER_H
diff --git a/scene/main/http_request.cpp b/scene/main/http_request.cpp
index 4afdb56f86..ae21775c55 100644
--- a/scene/main/http_request.cpp
+++ b/scene/main/http_request.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "http_request.h"
#include "version.h"
@@ -120,7 +121,7 @@ Error HTTPRequest::request(const String &p_url, const Vector<String> &p_custom_h
}
if (!has_user_agent) {
- headers.push_back("User-Agent: GodotEngine/" + String(VERSION_MKSTRING) + " (" + OS::get_singleton()->get_name() + ")");
+ headers.push_back("User-Agent: GodotEngine/" + String(VERSION_FULL_BUILD) + " (" + OS::get_singleton()->get_name() + ")");
}
if (!has_accept) {
@@ -523,6 +524,7 @@ void HTTPRequest::_bind_methods() {
ClassDB::bind_method(D_METHOD("_redirect_request"), &HTTPRequest::_redirect_request);
ClassDB::bind_method(D_METHOD("_request_done"), &HTTPRequest::_request_done);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "download_file", PROPERTY_HINT_FILE), "set_download_file", "get_download_file");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_threads"), "set_use_threads", "is_using_threads");
ADD_PROPERTY(PropertyInfo(Variant::INT, "body_size_limit", PROPERTY_HINT_RANGE, "-1,2000000000"), "set_body_size_limit", "get_body_size_limit");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_redirects", PROPERTY_HINT_RANGE, "-1,64"), "set_max_redirects", "get_max_redirects");
diff --git a/scene/main/http_request.h b/scene/main/http_request.h
index ab5a79c40d..eb5d020bc5 100644
--- a/scene/main/http_request.h
+++ b/scene/main/http_request.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef HTTPREQUEST_H
#define HTTPREQUEST_H
diff --git a/scene/main/instance_placeholder.cpp b/scene/main/instance_placeholder.cpp
index cbe30e05dd..1443d5efbf 100644
--- a/scene/main/instance_placeholder.cpp
+++ b/scene/main/instance_placeholder.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "instance_placeholder.h"
#include "io/resource_loader.h"
@@ -51,6 +52,7 @@ bool InstancePlaceholder::_get(const StringName &p_name, Variant &r_ret) const {
}
return false;
}
+
void InstancePlaceholder::_get_property_list(List<PropertyInfo> *p_list) const {
for (const List<PropSet>::Element *E = stored_values.front(); E; E = E->next()) {
@@ -72,13 +74,14 @@ String InstancePlaceholder::get_instance_path() const {
return path;
}
-void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene) {
- ERR_FAIL_COND(!is_inside_tree());
+Node *InstancePlaceholder::create_instance(bool p_replace, const Ref<PackedScene> &p_custom_scene) {
+
+ ERR_FAIL_COND_V(!is_inside_tree(), NULL);
Node *base = get_parent();
if (!base)
- return;
+ return NULL;
Ref<PackedScene> ps;
if (p_custom_scene.is_valid())
@@ -87,7 +90,7 @@ void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_s
ps = ResourceLoader::load(path, "PackedScene");
if (!ps.is_valid())
- return;
+ return NULL;
Node *scene = ps->instance();
scene->set_name(get_name());
int pos = get_position_in_parent();
@@ -96,11 +99,20 @@ void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_s
scene->set(E->get().name, E->get().value);
}
- queue_delete();
+ if (p_replace) {
+ queue_delete();
+ base->remove_child(this);
+ }
- base->remove_child(this);
base->add_child(scene);
base->move_child(scene, pos);
+
+ return scene;
+}
+
+void InstancePlaceholder::replace_by_instance(const Ref<PackedScene> &p_custom_scene) {
+ //Deprecated by
+ create_instance(true, p_custom_scene);
}
Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) {
@@ -123,6 +135,7 @@ Dictionary InstancePlaceholder::get_stored_values(bool p_with_order) {
void InstancePlaceholder::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_stored_values", "with_order"), &InstancePlaceholder::get_stored_values, DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("create_instance", "replace", "custom_scene"), &InstancePlaceholder::create_instance, DEFVAL(false), DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("replace_by_instance", "custom_scene"), &InstancePlaceholder::replace_by_instance, DEFVAL(Variant()));
ClassDB::bind_method(D_METHOD("get_instance_path"), &InstancePlaceholder::get_instance_path);
}
diff --git a/scene/main/instance_placeholder.h b/scene/main/instance_placeholder.h
index 375c87a035..2158257c93 100644
--- a/scene/main/instance_placeholder.h
+++ b/scene/main/instance_placeholder.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef INSTANCE_PLACEHOLDER_H
#define INSTANCE_PLACEHOLDER_H
@@ -59,6 +60,7 @@ public:
Dictionary get_stored_values(bool p_with_order = false);
+ Node *create_instance(bool p_replace = false, const Ref<PackedScene> &p_custom_scene = Ref<PackedScene>());
void replace_by_instance(const Ref<PackedScene> &p_custom_scene = Ref<PackedScene>());
InstancePlaceholder();
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index efc5d269a6..3643aedb85 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "node.h"
#include "core/core_string_names.h"
@@ -135,7 +136,6 @@ void Node::_notification(int p_notification) {
get_script_instance()->call_multilevel_reversed(SceneStringNames::get_singleton()->_ready, NULL, 0);
}
- //emit_signal(SceneStringNames::get_singleton()->enter_tree);
} break;
case NOTIFICATION_POSTINITIALIZE: {
@@ -176,14 +176,18 @@ void Node::_propagate_ready() {
data.children[i]->_propagate_ready();
}
data.blocked--;
+
+ notification(NOTIFICATION_POST_ENTER_TREE);
+
if (data.ready_first) {
data.ready_first = false;
notification(NOTIFICATION_READY);
+ emit_signal(SceneStringNames::get_singleton()->ready);
}
}
void Node::_propagate_enter_tree() {
- // this needs to happen to all childs before any enter_tree
+ // this needs to happen to all children before any enter_tree
if (data.parent) {
data.tree = data.parent->data.tree;
@@ -274,7 +278,7 @@ void Node::_propagate_exit_tree() {
get_script_instance()->call_multilevel(SceneStringNames::get_singleton()->_exit_tree, NULL, 0);
}
- emit_signal(SceneStringNames::get_singleton()->tree_exited);
+ emit_signal(SceneStringNames::get_singleton()->tree_exiting);
notification(NOTIFICATION_EXIT_TREE, true);
if (data.tree)
@@ -296,6 +300,8 @@ void Node::_propagate_exit_tree() {
data.ready_notified = false;
data.tree = NULL;
data.depth = -1;
+
+ emit_signal(SceneStringNames::get_singleton()->tree_exited);
}
void Node::move_child(Node *p_child, int p_pos) {
@@ -340,7 +346,8 @@ void Node::move_child(Node *p_child, int p_pos) {
data.children[i]->notification(NOTIFICATION_MOVED_IN_PARENT);
}
for (const Map<StringName, GroupData>::Element *E = p_child->data.grouped.front(); E; E = E->next()) {
- E->get().group->changed = true;
+ if (E->get().group)
+ E->get().group->changed = true;
}
data.blocked--;
@@ -473,7 +480,7 @@ bool Node::is_network_master() const {
ERR_FAIL_COND_V(!is_inside_tree(), false);
- return get_tree()->get_network_unique_id() == data.network_master;
+ return get_multiplayer()->get_network_unique_id() == data.network_master;
}
/***** RPC CONFIG ********/
@@ -663,200 +670,16 @@ Variant Node::_rpc_unreliable_id_bind(const Variant **p_args, int p_argcount, Va
}
void Node::rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount) {
-
ERR_FAIL_COND(!is_inside_tree());
-
- bool skip_rpc = false;
- bool call_local_native = false;
- bool call_local_script = false;
-
- if (p_peer_id == 0 || p_peer_id == get_tree()->get_network_unique_id() || (p_peer_id < 0 && p_peer_id != -get_tree()->get_network_unique_id())) {
- //check that send mode can use local call
-
- Map<StringName, RPCMode>::Element *E = data.rpc_methods.find(p_method);
- if (E) {
-
- switch (E->get()) {
-
- case RPC_MODE_DISABLED: {
- //do nothing
- } break;
- case RPC_MODE_REMOTE: {
- //do nothing also, no need to call local
- } break;
- case RPC_MODE_SYNC: {
- //call it, sync always results in call
- call_local_native = true;
- } break;
- case RPC_MODE_MASTER: {
- call_local_native = is_network_master();
- if (call_local_native) {
- skip_rpc = true; //no other master so..
- }
- } break;
- case RPC_MODE_SLAVE: {
- call_local_native = !is_network_master();
- } break;
- }
- }
-
- if (call_local_native) {
- // done below
- } else if (get_script_instance()) {
- //attempt with script
- ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rpc_mode(p_method);
-
- switch (rpc_mode) {
-
- case ScriptInstance::RPC_MODE_DISABLED: {
- //do nothing
- } break;
- case ScriptInstance::RPC_MODE_REMOTE: {
- //do nothing also, no need to call local
- } break;
- case ScriptInstance::RPC_MODE_SYNC: {
- //call it, sync always results in call
- call_local_script = true;
- } break;
- case ScriptInstance::RPC_MODE_MASTER: {
- call_local_script = is_network_master();
- if (call_local_script) {
- skip_rpc = true; //no other master so..
- }
- } break;
- case ScriptInstance::RPC_MODE_SLAVE: {
- call_local_script = !is_network_master();
- } break;
- }
- }
- }
-
- if (!skip_rpc) {
- get_tree()->_rpc(this, p_peer_id, p_unreliable, false, p_method, p_arg, p_argcount);
- }
-
- if (call_local_native) {
- Variant::CallError ce;
- call(p_method, p_arg, p_argcount, ce);
- if (ce.error != Variant::CallError::CALL_OK) {
- String error = Variant::get_call_error_text(this, p_method, p_arg, p_argcount, ce);
- error = "rpc() aborted in local call: - " + error;
- ERR_PRINTS(error);
- return;
- }
- }
-
- if (call_local_script) {
- Variant::CallError ce;
- ce.error = Variant::CallError::CALL_OK;
- get_script_instance()->call(p_method, p_arg, p_argcount, ce);
- if (ce.error != Variant::CallError::CALL_OK) {
- String error = Variant::get_call_error_text(this, p_method, p_arg, p_argcount, ce);
- error = "rpc() aborted in script local call: - " + error;
- ERR_PRINTS(error);
- return;
- }
- }
+ get_multiplayer()->rpcp(this, p_peer_id, p_unreliable, p_method, p_arg, p_argcount);
}
-/******** RSET *********/
-
void Node::rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value) {
-
ERR_FAIL_COND(!is_inside_tree());
-
- bool skip_rset = false;
-
- if (p_peer_id == 0 || p_peer_id == get_tree()->get_network_unique_id() || (p_peer_id < 0 && p_peer_id != -get_tree()->get_network_unique_id())) {
- //check that send mode can use local call
-
- bool set_local = false;
-
- Map<StringName, RPCMode>::Element *E = data.rpc_properties.find(p_property);
- if (E) {
-
- switch (E->get()) {
-
- case RPC_MODE_DISABLED: {
- //do nothing
- } break;
- case RPC_MODE_REMOTE: {
- //do nothing also, no need to call local
- } break;
- case RPC_MODE_SYNC: {
- //call it, sync always results in call
- set_local = true;
- } break;
- case RPC_MODE_MASTER: {
- set_local = is_network_master();
- if (set_local) {
- skip_rset = true;
- }
-
- } break;
- case RPC_MODE_SLAVE: {
- set_local = !is_network_master();
- } break;
- }
- }
-
- if (set_local) {
- bool valid;
- set(p_property, p_value, &valid);
-
- if (!valid) {
- String error = "rset() aborted in local set, property not found: - " + String(p_property);
- ERR_PRINTS(error);
- return;
- }
- } else if (get_script_instance()) {
- //attempt with script
- ScriptInstance::RPCMode rpc_mode = get_script_instance()->get_rset_mode(p_property);
-
- switch (rpc_mode) {
-
- case ScriptInstance::RPC_MODE_DISABLED: {
- //do nothing
- } break;
- case ScriptInstance::RPC_MODE_REMOTE: {
- //do nothing also, no need to call local
- } break;
- case ScriptInstance::RPC_MODE_SYNC: {
- //call it, sync always results in call
- set_local = true;
- } break;
- case ScriptInstance::RPC_MODE_MASTER: {
- set_local = is_network_master();
- if (set_local) {
- skip_rset = true;
- }
- } break;
- case ScriptInstance::RPC_MODE_SLAVE: {
- set_local = !is_network_master();
- } break;
- }
-
- if (set_local) {
-
- bool valid = get_script_instance()->set(p_property, p_value);
-
- if (!valid) {
- String error = "rset() aborted in local script set, property not found: - " + String(p_property);
- ERR_PRINTS(error);
- return;
- }
- }
- }
- }
-
- if (skip_rset)
- return;
-
- const Variant *vptr = &p_value;
-
- get_tree()->_rpc(this, p_peer_id, p_unreliable, true, p_property, &vptr, 1);
+ get_multiplayer()->rsetp(this, p_peer_id, p_unreliable, p_property, p_value);
}
+/******** RSET *********/
void Node::rset(const StringName &p_property, const Variant &p_value) {
rsetp(0, false, p_property, p_value);
@@ -878,6 +701,30 @@ void Node::rset_unreliable_id(int p_peer_id, const StringName &p_property, const
}
//////////// end of rpc
+Ref<MultiplayerAPI> Node::get_multiplayer() const {
+ if (multiplayer.is_valid())
+ return multiplayer;
+ if (!is_inside_tree())
+ return Ref<MultiplayerAPI>();
+ return get_tree()->get_multiplayer();
+}
+
+Ref<MultiplayerAPI> Node::get_custom_multiplayer() const {
+ return multiplayer;
+}
+
+void Node::set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
+
+ multiplayer = p_multiplayer;
+}
+
+const Map<StringName, Node::RPCMode>::Element *Node::get_node_rpc_mode(const StringName &p_method) {
+ return data.rpc_methods.find(p_method);
+}
+
+const Map<StringName, Node::RPCMode>::Element *Node::get_node_rset_mode(const StringName &p_property) {
+ return data.rpc_properties.find(p_property);
+}
bool Node::can_call_rpc(const StringName &p_method, int p_from) const {
@@ -1135,9 +982,23 @@ void Node::_set_name_nocheck(const StringName &p_name) {
data.name = p_name;
}
+String Node::invalid_character = ". : @ / \"";
+
+bool Node::_validate_node_name(String &p_name) {
+ String name = p_name;
+ Vector<String> chars = Node::invalid_character.split(" ");
+ for (int i = 0; i < chars.size(); i++) {
+ name = name.replace(chars[i], "");
+ }
+ bool is_valid = name == p_name;
+ p_name = name;
+ return is_valid;
+}
+
void Node::set_name(const String &p_name) {
- String name = p_name.replace(":", "").replace("/", "").replace("@", "");
+ String name = p_name;
+ _validate_node_name(name);
ERR_FAIL_COND(name == "");
data.name = name;
@@ -1198,13 +1059,13 @@ void Node::_validate_child_name(Node *p_child, bool p_force_human_readable) {
unique = false;
} else {
//check if exists
- Node **childs = data.children.ptrw();
+ Node **children = data.children.ptrw();
int cc = data.children.size();
for (int i = 0; i < cc; i++) {
- if (childs[i] == p_child)
+ if (children[i] == p_child)
continue;
- if (childs[i]->data.name == p_child->data.name) {
+ if (children[i]->data.name == p_child->data.name) {
unique = false;
break;
}
@@ -1307,7 +1168,7 @@ void Node::_add_child_nocheck(Node *p_child, const StringName &p_name) {
}
/* Notify */
- //recognize childs created in this node constructor
+ //recognize children created in this node constructor
p_child->data.parent_owned = data.in_constructor;
add_child_notify(p_child);
}
@@ -1864,11 +1725,18 @@ bool Node::has_persistent_groups() const {
return false;
}
-void Node::_print_tree(const Node *p_node) {
+void Node::_print_tree_pretty(const String prefix, const bool last) {
- print_line(String(p_node->get_path_to(this)));
- for (int i = 0; i < data.children.size(); i++)
- data.children[i]->_print_tree(p_node);
+ String new_prefix = last ? String::utf8(" â”–â•´") : String::utf8(" â” â•´");
+ print_line(prefix + new_prefix + String(get_name()));
+ for (int i = 0; i < data.children.size(); i++) {
+ new_prefix = last ? String::utf8(" ") : String::utf8(" ┃ ");
+ data.children[i]->_print_tree_pretty(prefix + new_prefix, i == data.children.size() - 1);
+ }
+}
+
+void Node::print_tree_pretty() {
+ _print_tree_pretty("", true);
}
void Node::print_tree() {
@@ -1876,6 +1744,12 @@ void Node::print_tree() {
_print_tree(this);
}
+void Node::_print_tree(const Node *p_node) {
+ print_line(String(p_node->get_path_to(this)));
+ for (int i = 0; i < data.children.size(); i++)
+ data.children[i]->_print_tree(p_node);
+}
+
void Node::_propagate_reverse_notification(int p_notification) {
data.blocked++;
@@ -2006,7 +1880,7 @@ void Node::set_editable_instance(Node *p_node, bool p_editable) {
if (!p_editable) {
data.editable_instances.erase(p);
// Avoid this flag being needlessly saved;
- // also give more visual feedback if editable children is reenabled
+ // also give more visual feedback if editable children is re-enabled
set_display_folded(false);
} else {
data.editable_instances[p] = true;
@@ -2110,6 +1984,7 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
StringName script_property_name = CoreStringNames::get_singleton()->_script;
+ List<const Node *> hidden_roots;
List<const Node *> node_tree;
node_tree.push_front(this);
@@ -2120,11 +1995,16 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
for (int i = 0; i < N->get()->get_child_count(); ++i) {
+ Node *descendant = N->get()->get_child(i);
// Skip nodes not really belonging to the instanced hierarchy; they'll be processed normally later
- if (N->get()->get_child(i)->data.owner != this)
+ // but remember non-instanced nodes that are hidden below instanced ones
+ if (descendant->data.owner != this) {
+ if (descendant->get_parent() && descendant->get_parent() != this && descendant->get_parent()->data.owner == this)
+ hidden_roots.push_back(descendant);
continue;
+ }
- node_tree.push_back(N->get()->get_child(i));
+ node_tree.push_back(descendant);
}
}
}
@@ -2153,15 +2033,18 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
if (name == script_property_name)
continue;
- Variant value = N->get()->get(name);
- // Duplicate dictionaries and arrays, mainly needed for __meta__
- if (value.get_type() == Variant::DICTIONARY) {
- value = Dictionary(value).copy();
- } else if (value.get_type() == Variant::ARRAY) {
- value = Array(value).duplicate();
- }
+ Variant value = N->get()->get(name).duplicate(true);
+
+ if (E->get().usage & PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE) {
- current_node->set(name, value);
+ Resource *res = Object::cast_to<Resource>(value);
+ if (res) // Duplicate only if it's a resource
+ current_node->set(name, res->duplicate());
+
+ } else {
+
+ current_node->set(name, value);
+ }
}
}
@@ -2201,6 +2084,34 @@ Node *Node::_duplicate(int p_flags, Map<const Node *, Node *> *r_duplimap) const
}
node->add_child(dup);
+ if (i < node->get_child_count() - 1) {
+ node->move_child(dup, i);
+ }
+ }
+
+ for (List<const Node *>::Element *E = hidden_roots.front(); E; E = E->next()) {
+
+ Node *parent = node->get_node(get_path_to(E->get()->data.parent));
+ if (!parent) {
+
+ memdelete(node);
+ return NULL;
+ }
+
+ Node *dup = E->get()->_duplicate(p_flags, r_duplimap);
+ if (!dup) {
+
+ memdelete(node);
+ return NULL;
+ }
+
+ parent->add_child(dup);
+ int pos = E->get()->get_position_in_parent();
+
+ if (pos < parent->get_child_count() - 1) {
+
+ parent->move_child(dup, pos);
+ }
}
return node;
@@ -2266,13 +2177,7 @@ void Node::_duplicate_and_reown(Node *p_new_parent, const Map<Node *, Node *> &p
continue;
String name = E->get().name;
- Variant value = get(name);
- // Duplicate dictionaries and arrays, mainly needed for __meta__
- if (value.get_type() == Variant::DICTIONARY) {
- value = Dictionary(value).copy();
- } else if (value.get_type() == Variant::ARRAY) {
- value = Array(value).duplicate();
- }
+ Variant value = get(name).duplicate(true);
node->set(name, value);
}
@@ -2455,7 +2360,10 @@ void Node::replace_by(Node *p_node, bool p_keep_data) {
Node *child = get_child(0);
remove_child(child);
- p_node->add_child(child);
+ if (!child->is_owned_by_parent()) {
+ // add the custom children to the p_node
+ p_node->add_child(child);
+ }
}
p_node->set_owner(owner);
@@ -2676,18 +2584,21 @@ Array Node::_get_children() const {
return arr;
}
-#ifdef TOOLS_ENABLED
void Node::set_import_path(const NodePath &p_import_path) {
+#ifdef TOOLS_ENABLED
data.import_path = p_import_path;
+#endif
}
NodePath Node::get_import_path() const {
+#ifdef TOOLS_ENABLED
return data.import_path;
-}
-
+#else
+ return NodePath();
#endif
+}
static void _add_nodes_to_options(const Node *p_base, const Node *p_node, List<String> *r_options) {
@@ -2790,6 +2701,7 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_and_skip"), &Node::remove_and_skip);
ClassDB::bind_method(D_METHOD("get_index"), &Node::get_index);
ClassDB::bind_method(D_METHOD("print_tree"), &Node::print_tree);
+ ClassDB::bind_method(D_METHOD("print_tree_pretty"), &Node::print_tree_pretty);
ClassDB::bind_method(D_METHOD("set_filename", "filename"), &Node::set_filename);
ClassDB::bind_method(D_METHOD("get_filename"), &Node::get_filename);
ClassDB::bind_method(D_METHOD("propagate_notification", "what"), &Node::propagate_notification);
@@ -2839,15 +2751,15 @@ void Node::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_network_master"), &Node::is_network_master);
+ ClassDB::bind_method(D_METHOD("get_multiplayer"), &Node::get_multiplayer);
+ ClassDB::bind_method(D_METHOD("get_custom_multiplayer"), &Node::get_custom_multiplayer);
+ ClassDB::bind_method(D_METHOD("set_custom_multiplayer", "api"), &Node::set_custom_multiplayer);
ClassDB::bind_method(D_METHOD("rpc_config", "method", "mode"), &Node::rpc_config);
ClassDB::bind_method(D_METHOD("rset_config", "property", "mode"), &Node::rset_config);
-#ifdef TOOLS_ENABLED
ClassDB::bind_method(D_METHOD("_set_import_path", "import_path"), &Node::set_import_path);
ClassDB::bind_method(D_METHOD("_get_import_path"), &Node::get_import_path);
- ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_import_path", "_get_import_path");
-
-#endif
+ ADD_PROPERTYNZ(PropertyInfo(Variant::NODE_PATH, "_import_path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_import_path", "_get_import_path");
{
MethodInfo mi;
@@ -2905,8 +2817,10 @@ void Node::_bind_methods() {
BIND_ENUM_CONSTANT(DUPLICATE_SCRIPTS);
BIND_ENUM_CONSTANT(DUPLICATE_USE_INSTANCING);
+ ADD_SIGNAL(MethodInfo("ready"));
ADD_SIGNAL(MethodInfo("renamed"));
ADD_SIGNAL(MethodInfo("tree_entered"));
+ ADD_SIGNAL(MethodInfo("tree_exiting"));
ADD_SIGNAL(MethodInfo("tree_exited"));
//ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/process" ),"set_process","is_processing") ;
@@ -2915,7 +2829,12 @@ void Node::_bind_methods() {
//ADD_PROPERTYNZ( PropertyInfo( Variant::BOOL, "process/unhandled_input" ), "set_process_unhandled_input","is_processing_unhandled_input" ) ;
ADD_GROUP("Pause", "pause_");
ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "pause_mode", PROPERTY_HINT_ENUM, "Inherit,Stop,Process"), "set_pause_mode", "get_pause_mode");
- ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_display_folded", "is_displayed_folded");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::BOOL, "editor/display_folded", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_display_folded", "is_displayed_folded");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "", 0), "set_name", "get_name");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::STRING, "filename", PROPERTY_HINT_NONE, "", 0), "set_filename", "get_filename");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "owner", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_owner", "get_owner");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "", "get_multiplayer");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::OBJECT, "custom_multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_custom_multiplayer", "get_custom_multiplayer");
BIND_VMETHOD(MethodInfo("_process", PropertyInfo(Variant::REAL, "delta")));
BIND_VMETHOD(MethodInfo("_physics_process", PropertyInfo(Variant::REAL, "delta")));
diff --git a/scene/main/node.h b/scene/main/node.h
index 2b71b71c8d..540f34cba7 100644
--- a/scene/main/node.h
+++ b/scene/main/node.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef NODE_H
#define NODE_H
@@ -103,7 +104,7 @@ private:
StringName name;
SceneTree *tree;
bool inside_tree;
- bool ready_notified; //this is a small hack, so if a node is added during _ready() to the tree, it corretly gets the _ready() notification
+ bool ready_notified; //this is a small hack, so if a node is added during _ready() to the tree, it correctly gets the _ready() notification
bool ready_first;
#ifdef TOOLS_ENABLED
NodePath import_path; //path used when imported, used by scene editors to keep tracking
@@ -150,6 +151,9 @@ private:
NAME_CASING_SNAKE_CASE
};
+ Ref<MultiplayerAPI> multiplayer;
+
+ void _print_tree_pretty(const String prefix, const bool last);
void _print_tree(const Node *p_node);
Node *_get_node(const NodePath &p_path) const;
@@ -186,6 +190,12 @@ private:
void _set_tree(SceneTree *p_tree);
+#ifdef TOOLS_ENABLED
+ friend class SceneTreeEditor;
+#endif
+ static String invalid_character;
+ static bool _validate_node_name(String &p_name);
+
protected:
void _block() { data.blocked++; }
void _unblock() { data.blocked--; }
@@ -227,6 +237,7 @@ public:
NOTIFICATION_TRANSLATION_CHANGED = 24,
NOTIFICATION_INTERNAL_PROCESS = 25,
NOTIFICATION_INTERNAL_PHYSICS_PROCESS = 26,
+ NOTIFICATION_POST_ENTER_TREE = 27,
};
@@ -286,6 +297,7 @@ public:
int get_index() const;
void print_tree();
+ void print_tree_pretty();
void set_filename(const String &p_filename);
String get_filename() const;
@@ -363,16 +375,14 @@ public:
void queue_delete();
- //shitty hacks for speed
+ //hacks for speed
static void set_human_readable_collision_renaming(bool p_enabled);
static void init_node_hrcr();
void force_parent_owned() { data.parent_owned = true; } //hack to avoid duplicate nodes
-#ifdef TOOLS_ENABLED
void set_import_path(const NodePath &p_import_path); //path used when imported, used by scene editors to keep tracking
NodePath get_import_path() const;
-#endif
bool is_owned_by_parent() const;
@@ -402,15 +412,20 @@ public:
void rpc_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
void rpc_unreliable_id(int p_peer_id, const StringName &p_method, VARIANT_ARG_LIST); //rpc call, honors RPCMode
- void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
-
void rset(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rset_unreliable(const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rset_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
void rset_unreliable_id(int p_peer_id, const StringName &p_property, const Variant &p_value); //remote set call, honors RPCMode
+ void rpcp(int p_peer_id, bool p_unreliable, const StringName &p_method, const Variant **p_arg, int p_argcount);
void rsetp(int p_peer_id, bool p_unreliable, const StringName &p_property, const Variant &p_value);
+ Ref<MultiplayerAPI> get_multiplayer() const;
+ Ref<MultiplayerAPI> get_custom_multiplayer() const;
+ void set_custom_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
+ const Map<StringName, RPCMode>::Element *get_node_rpc_mode(const StringName &p_method);
+ const Map<StringName, RPCMode>::Element *get_node_rset_mode(const StringName &p_property);
+
bool can_call_rpc(const StringName &p_method, int p_from) const;
bool can_call_rset(const StringName &p_property, int p_from) const;
diff --git a/scene/main/resource_preloader.cpp b/scene/main/resource_preloader.cpp
index 35bb6ef7e8..dbe7daa604 100644
--- a/scene/main/resource_preloader.cpp
+++ b/scene/main/resource_preloader.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "resource_preloader.h"
void ResourcePreloader::_set_resources(const Array &p_data) {
@@ -160,7 +161,7 @@ void ResourcePreloader::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_resource", "name"), &ResourcePreloader::get_resource);
ClassDB::bind_method(D_METHOD("get_resource_list"), &ResourcePreloader::_get_resource_list);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "resources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_resources", "_get_resources");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "resources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_resources", "_get_resources");
}
ResourcePreloader::ResourcePreloader() {
diff --git a/scene/main/resource_preloader.h b/scene/main/resource_preloader.h
index 40e900a492..98c7b21f37 100644
--- a/scene/main/resource_preloader.h
+++ b/scene/main/resource_preloader.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RESOURCE_PRELOADER_H
#define RESOURCE_PRELOADER_H
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index deb40800bc..607dbebf6c 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,17 +27,20 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "scene_tree.h"
#include "editor/editor_node.h"
#include "io/marshalls.h"
#include "io/resource_loader.h"
+#include "main/input_default.h"
#include "message_queue.h"
#include "node.h"
#include "os/keyboard.h"
#include "os/os.h"
#include "print_string.h"
#include "project_settings.h"
+#include "scene/resources/dynamic_font.h"
#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/packed_scene.h"
@@ -53,6 +56,8 @@ void SceneTreeTimer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_time_left", "time"), &SceneTreeTimer::set_time_left);
ClassDB::bind_method(D_METHOD("get_time_left"), &SceneTreeTimer::get_time_left);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_left"), "set_time_left", "get_time_left");
+
ADD_SIGNAL(MethodInfo("timeout"));
}
@@ -390,13 +395,12 @@ void SceneTree::input_event(const Ref<InputEvent> &p_event) {
if (Engine::get_singleton()->is_editor_hint() && (Object::cast_to<InputEventJoypadButton>(p_event.ptr()) || Object::cast_to<InputEventJoypadMotion>(*p_event)))
return; //avoid joy input on editor
+ current_event++;
root_lock++;
- //last_id=p_event.ID;
input_handled = false;
Ref<InputEvent> ev = p_event;
- ev->set_id(++last_id); //this should work better
MainLoop::input_event(ev);
@@ -481,7 +485,7 @@ bool SceneTree::idle(float p_time) {
idle_process_time = p_time;
- _network_poll();
+ multiplayer->poll();
emit_signal("idle_frame");
@@ -498,6 +502,11 @@ bool SceneTree::idle(float p_time) {
last_screen_size = win_size;
_update_root_rect();
+ if (use_font_oversampling) {
+ DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width;
+ DynamicFont::update_oversampling();
+ }
+
emit_signal("screen_resized");
}
@@ -607,9 +616,18 @@ void SceneTree::_notification(int p_notification) {
}
} break;
case NOTIFICATION_OS_MEMORY_WARNING:
+ case NOTIFICATION_WM_MOUSE_ENTER:
+ case NOTIFICATION_WM_MOUSE_EXIT:
case NOTIFICATION_WM_FOCUS_IN:
case NOTIFICATION_WM_FOCUS_OUT: {
+ if (p_notification == NOTIFICATION_WM_FOCUS_IN) {
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ if (id) {
+ id->ensure_touch_mouse_raised();
+ }
+ }
+
get_root()->propagate_notification(p_notification);
} break;
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -935,11 +953,6 @@ void SceneMainLoop::_update_listener_2d() {
}
*/
-uint32_t SceneTree::get_last_event_id() const {
-
- return last_id;
-}
-
Variant SceneTree::_call_group_flags(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
r_error.error = Variant::CallError::CALL_OK;
@@ -988,6 +1001,10 @@ int64_t SceneTree::get_frame() const {
return current_frame;
}
+int64_t SceneTree::get_event_count() const {
+
+ return current_event;
+}
Array SceneTree::_get_nodes_in_group(const StringName &p_group) {
@@ -1188,16 +1205,20 @@ void SceneTree::set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, c
_update_root_rect();
}
-#ifdef TOOLS_ENABLED
void SceneTree::set_edited_scene_root(Node *p_node) {
+#ifdef TOOLS_ENABLED
edited_scene_root = p_node;
+#endif
}
Node *SceneTree::get_edited_scene_root() const {
+#ifdef TOOLS_ENABLED
return edited_scene_root;
-}
+#else
+ return NULL;
#endif
+}
void SceneTree::set_current_scene(Node *p_scene) {
@@ -1624,16 +1645,11 @@ Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pa
void SceneTree::_network_peer_connected(int p_id) {
- connected_peers.insert(p_id);
- path_get_cache.insert(p_id, PathGetCache());
-
emit_signal("network_peer_connected", p_id);
}
void SceneTree::_network_peer_disconnected(int p_id) {
- connected_peers.erase(p_id);
- path_get_cache.erase(p_id); //I no longer need your cache, sorry
emit_signal("network_peer_disconnected", p_id);
}
@@ -1652,466 +1668,70 @@ void SceneTree::_server_disconnected() {
emit_signal("server_disconnected");
}
-void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer) {
- if (network_peer.is_valid()) {
- network_peer->disconnect("peer_connected", this, "_network_peer_connected");
- network_peer->disconnect("peer_disconnected", this, "_network_peer_disconnected");
- network_peer->disconnect("connection_succeeded", this, "_connected_to_server");
- network_peer->disconnect("connection_failed", this, "_connection_failed");
- network_peer->disconnect("server_disconnected", this, "_server_disconnected");
- connected_peers.clear();
- path_get_cache.clear();
- path_send_cache.clear();
- last_send_cache_id = 1;
+Ref<MultiplayerAPI> SceneTree::get_multiplayer() const {
+ return multiplayer;
+}
+
+void SceneTree::set_multiplayer(Ref<MultiplayerAPI> p_multiplayer) {
+ ERR_FAIL_COND(!p_multiplayer.is_valid());
+
+ if (multiplayer.is_valid()) {
+ multiplayer->disconnect("network_peer_connected", this, "_network_peer_connected");
+ multiplayer->disconnect("network_peer_disconnected", this, "_network_peer_disconnected");
+ multiplayer->disconnect("connected_to_server", this, "_connected_to_server");
+ multiplayer->disconnect("connection_failed", this, "_connection_failed");
+ multiplayer->disconnect("server_disconnected", this, "_server_disconnected");
}
- ERR_EXPLAIN("Supplied NetworkedNetworkPeer must be connecting or connected.");
- ERR_FAIL_COND(p_network_peer.is_valid() && p_network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED);
+ multiplayer = p_multiplayer;
+ multiplayer->set_root_node(root);
- network_peer = p_network_peer;
+ multiplayer->connect("network_peer_connected", this, "_network_peer_connected");
+ multiplayer->connect("network_peer_disconnected", this, "_network_peer_disconnected");
+ multiplayer->connect("connected_to_server", this, "_connected_to_server");
+ multiplayer->connect("connection_failed", this, "_connection_failed");
+ multiplayer->connect("server_disconnected", this, "_server_disconnected");
+}
- if (network_peer.is_valid()) {
- network_peer->connect("peer_connected", this, "_network_peer_connected");
- network_peer->connect("peer_disconnected", this, "_network_peer_disconnected");
- network_peer->connect("connection_succeeded", this, "_connected_to_server");
- network_peer->connect("connection_failed", this, "_connection_failed");
- network_peer->connect("server_disconnected", this, "_server_disconnected");
- }
+void SceneTree::set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer) {
+
+ multiplayer->set_network_peer(p_network_peer);
+}
+
+Ref<NetworkedMultiplayerPeer> SceneTree::get_network_peer() const {
+
+ return multiplayer->get_network_peer();
}
bool SceneTree::is_network_server() const {
- ERR_FAIL_COND_V(!network_peer.is_valid(), false);
- return network_peer->is_server();
+ return multiplayer->is_network_server();
}
bool SceneTree::has_network_peer() const {
- return network_peer.is_valid();
+ return multiplayer->has_network_peer();
}
int SceneTree::get_network_unique_id() const {
- ERR_FAIL_COND_V(!network_peer.is_valid(), 0);
- return network_peer->get_unique_id();
+ return multiplayer->get_network_unique_id();
}
Vector<int> SceneTree::get_network_connected_peers() const {
- ERR_FAIL_COND_V(!network_peer.is_valid(), Vector<int>());
-
- Vector<int> ret;
- for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) {
- ret.push_back(E->get());
- }
- return ret;
+ return multiplayer->get_network_connected_peers();
}
int SceneTree::get_rpc_sender_id() const {
- return rpc_sender_id;
+ return multiplayer->get_rpc_sender_id();
}
void SceneTree::set_refuse_new_network_connections(bool p_refuse) {
- ERR_FAIL_COND(!network_peer.is_valid());
- network_peer->set_refuse_new_connections(p_refuse);
+ multiplayer->set_refuse_new_network_connections(p_refuse);
}
bool SceneTree::is_refusing_new_network_connections() const {
-
- ERR_FAIL_COND_V(!network_peer.is_valid(), false);
-
- return network_peer->is_refusing_new_connections();
-}
-
-void SceneTree::_rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount) {
-
- if (network_peer.is_null()) {
- ERR_EXPLAIN("Attempt to remote call/set when networking is not active in SceneTree.");
- ERR_FAIL();
- }
-
- if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_CONNECTING) {
- ERR_EXPLAIN("Attempt to remote call/set when networking is not connected yet in SceneTree.");
- ERR_FAIL();
- }
-
- if (network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED) {
- ERR_EXPLAIN("Attempt to remote call/set when networking is disconnected.");
- ERR_FAIL();
- }
-
- if (p_argcount > 255) {
- ERR_EXPLAIN("Too many arguments >255.");
- ERR_FAIL();
- }
-
- if (p_to != 0 && !connected_peers.has(ABS(p_to))) {
- if (p_to == get_network_unique_id()) {
- ERR_EXPLAIN("Attempt to remote call/set yourself! unique ID: " + itos(get_network_unique_id()));
- } else {
- ERR_EXPLAIN("Attempt to remote call unexisting ID: " + itos(p_to));
- }
-
- ERR_FAIL();
- }
-
- NodePath from_path = p_from->get_path();
- ERR_FAIL_COND(from_path.is_empty());
-
- //see if the path is cached
- PathSentCache *psc = path_send_cache.getptr(from_path);
- if (!psc) {
- //path is not cached, create
- path_send_cache[from_path] = PathSentCache();
- psc = path_send_cache.getptr(from_path);
- psc->id = last_send_cache_id++;
- }
-
- //create base packet, lots of harcode because it must be tight
-
- int ofs = 0;
-
-#define MAKE_ROOM(m_amount) \
- if (packet_cache.size() < m_amount) packet_cache.resize(m_amount);
-
- //encode type
- MAKE_ROOM(1);
- packet_cache[0] = p_set ? NETWORK_COMMAND_REMOTE_SET : NETWORK_COMMAND_REMOTE_CALL;
- ofs += 1;
-
- //encode ID
- MAKE_ROOM(ofs + 4);
- encode_uint32(psc->id, &packet_cache[ofs]);
- ofs += 4;
-
- //encode function name
- CharString name = String(p_name).utf8();
- int len = encode_cstring(name.get_data(), NULL);
- MAKE_ROOM(ofs + len);
- encode_cstring(name.get_data(), &packet_cache[ofs]);
- ofs += len;
-
- if (p_set) {
- //set argument
- Error err = encode_variant(*p_arg[0], NULL, len);
- ERR_FAIL_COND(err != OK);
- MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[0], &packet_cache[ofs], len);
- ofs += len;
-
- } else {
- //call arguments
- MAKE_ROOM(ofs + 1);
- packet_cache[ofs] = p_argcount;
- ofs += 1;
- for (int i = 0; i < p_argcount; i++) {
- Error err = encode_variant(*p_arg[i], NULL, len);
- ERR_FAIL_COND(err != OK);
- MAKE_ROOM(ofs + len);
- encode_variant(*p_arg[i], &packet_cache[ofs], len);
- ofs += len;
- }
- }
-
- //see if all peers have cached path (is so, call can be fast)
- bool has_all_peers = true;
-
- List<int> peers_to_add; //if one is missing, take note to add it
-
- for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) {
-
- if (p_to < 0 && E->get() == -p_to)
- continue; //continue, excluded
-
- if (p_to > 0 && E->get() != p_to)
- continue; //continue, not for this peer
-
- Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get());
-
- if (!F || F->get() == false) {
- //path was not cached, or was cached but is unconfirmed
- if (!F) {
- //not cached at all, take note
- peers_to_add.push_back(E->get());
- }
-
- has_all_peers = false;
- }
- }
-
- //those that need to be added, send a message for this
-
- for (List<int>::Element *E = peers_to_add.front(); E; E = E->next()) {
-
- //encode function name
- CharString pname = String(from_path).utf8();
- int len = encode_cstring(pname.get_data(), NULL);
-
- Vector<uint8_t> packet;
-
- packet.resize(1 + 4 + len);
- packet[0] = NETWORK_COMMAND_SIMPLIFY_PATH;
- encode_uint32(psc->id, &packet[1]);
- encode_cstring(pname.get_data(), &packet[5]);
-
- network_peer->set_target_peer(E->get()); //to all of you
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
- network_peer->put_packet(packet.ptr(), packet.size());
-
- psc->confirmed_peers.insert(E->get(), false); //insert into confirmed, but as false since it was not confirmed
- }
-
- //take chance and set transfer mode, since all send methods will use it
- network_peer->set_transfer_mode(p_unreliable ? NetworkedMultiplayerPeer::TRANSFER_MODE_UNRELIABLE : NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
-
- if (has_all_peers) {
-
- //they all have verified paths, so send fast
- network_peer->set_target_peer(p_to); //to all of you
- network_peer->put_packet(packet_cache.ptr(), ofs); //a message with love
- } else {
- //not all verified path, so send one by one
-
- //apend path at the end, since we will need it for some packets
- CharString pname = String(from_path).utf8();
- int path_len = encode_cstring(pname.get_data(), NULL);
- MAKE_ROOM(ofs + path_len);
- encode_cstring(pname.get_data(), &packet_cache[ofs]);
-
- for (Set<int>::Element *E = connected_peers.front(); E; E = E->next()) {
-
- if (p_to < 0 && E->get() == -p_to)
- continue; //continue, excluded
-
- if (p_to > 0 && E->get() != p_to)
- continue; //continue, not for this peer
-
- Map<int, bool>::Element *F = psc->confirmed_peers.find(E->get());
- ERR_CONTINUE(!F); //should never happen
-
- network_peer->set_target_peer(E->get()); //to this one specifically
-
- if (F->get() == true) {
- //this one confirmed path, so use id
- encode_uint32(psc->id, &packet_cache[1]);
- network_peer->put_packet(packet_cache.ptr(), ofs);
- } else {
- //this one did not confirm path yet, so use entire path (sorry!)
- encode_uint32(0x80000000 | ofs, &packet_cache[1]); //offset to path and flag
- network_peer->put_packet(packet_cache.ptr(), ofs + path_len);
- }
- }
- }
-}
-
-void SceneTree::_network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len) {
-
- ERR_FAIL_COND(p_packet_len < 5);
-
- uint8_t packet_type = p_packet[0];
-
- switch (packet_type) {
-
- case NETWORK_COMMAND_REMOTE_CALL:
- case NETWORK_COMMAND_REMOTE_SET: {
-
- ERR_FAIL_COND(p_packet_len < 5);
- uint32_t target = decode_uint32(&p_packet[1]);
-
- Node *node = NULL;
-
- if (target & 0x80000000) {
- //use full path (not cached yet)
-
- int ofs = target & 0x7FFFFFFF;
- ERR_FAIL_COND(ofs >= p_packet_len);
-
- String paths;
- paths.parse_utf8((const char *)&p_packet[ofs], p_packet_len - ofs);
-
- NodePath np = paths;
-
- node = get_root()->get_node(np);
- if (node == NULL) {
- ERR_EXPLAIN("Failed to get path from RPC: " + String(np));
- ERR_FAIL_COND(node == NULL);
- }
- } else {
- //use cached path
- int id = target;
-
- Map<int, PathGetCache>::Element *E = path_get_cache.find(p_from);
- ERR_FAIL_COND(!E);
-
- Map<int, PathGetCache::NodeInfo>::Element *F = E->get().nodes.find(id);
- ERR_FAIL_COND(!F);
-
- PathGetCache::NodeInfo *ni = &F->get();
- //do proper caching later
-
- node = get_root()->get_node(ni->path);
- if (node == NULL) {
- ERR_EXPLAIN("Failed to get cached path from RPC: " + String(ni->path));
- ERR_FAIL_COND(node == NULL);
- }
- }
-
- ERR_FAIL_COND(p_packet_len < 6);
-
- //detect cstring end
- int len_end = 5;
- for (; len_end < p_packet_len; len_end++) {
- if (p_packet[len_end] == 0) {
- break;
- }
- }
-
- ERR_FAIL_COND(len_end >= p_packet_len);
-
- StringName name = String::utf8((const char *)&p_packet[5]);
-
- if (packet_type == NETWORK_COMMAND_REMOTE_CALL) {
-
- if (!node->can_call_rpc(name, p_from))
- return;
-
- int ofs = len_end + 1;
-
- ERR_FAIL_COND(ofs >= p_packet_len);
-
- int argc = p_packet[ofs];
- Vector<Variant> args;
- Vector<const Variant *> argp;
- args.resize(argc);
- argp.resize(argc);
-
- ofs++;
-
- for (int i = 0; i < argc; i++) {
-
- ERR_FAIL_COND(ofs >= p_packet_len);
- int vlen;
- Error err = decode_variant(args[i], &p_packet[ofs], p_packet_len - ofs, &vlen);
- ERR_FAIL_COND(err != OK);
- //args[i]=p_packet[3+i];
- argp[i] = &args[i];
- ofs += vlen;
- }
-
- Variant::CallError ce;
-
- node->call(name, (const Variant **)argp.ptr(), argc, ce);
- if (ce.error != Variant::CallError::CALL_OK) {
- String error = Variant::get_call_error_text(node, name, (const Variant **)argp.ptr(), argc, ce);
- error = "RPC - " + error;
- ERR_PRINTS(error);
- }
-
- } else {
-
- if (!node->can_call_rset(name, p_from))
- return;
-
- int ofs = len_end + 1;
-
- ERR_FAIL_COND(ofs >= p_packet_len);
-
- Variant value;
- decode_variant(value, &p_packet[ofs], p_packet_len - ofs);
-
- bool valid;
-
- node->set(name, value, &valid);
- if (!valid) {
- String error = "Error setting remote property '" + String(name) + "', not found in object of type " + node->get_class();
- ERR_PRINTS(error);
- }
- }
-
- } break;
- case NETWORK_COMMAND_SIMPLIFY_PATH: {
-
- ERR_FAIL_COND(p_packet_len < 5);
- int id = decode_uint32(&p_packet[1]);
-
- String paths;
- paths.parse_utf8((const char *)&p_packet[5], p_packet_len - 5);
-
- NodePath path = paths;
-
- if (!path_get_cache.has(p_from)) {
- path_get_cache[p_from] = PathGetCache();
- }
-
- PathGetCache::NodeInfo ni;
- ni.path = path;
- ni.instance = 0;
-
- path_get_cache[p_from].nodes[id] = ni;
-
- {
- //send ack
-
- //encode path
- CharString pname = String(path).utf8();
- int len = encode_cstring(pname.get_data(), NULL);
-
- Vector<uint8_t> packet;
-
- packet.resize(1 + len);
- packet[0] = NETWORK_COMMAND_CONFIRM_PATH;
- encode_cstring(pname.get_data(), &packet[1]);
-
- network_peer->set_transfer_mode(NetworkedMultiplayerPeer::TRANSFER_MODE_RELIABLE);
- network_peer->set_target_peer(p_from);
- network_peer->put_packet(packet.ptr(), packet.size());
- }
- } break;
- case NETWORK_COMMAND_CONFIRM_PATH: {
-
- String paths;
- paths.parse_utf8((const char *)&p_packet[1], p_packet_len - 1);
-
- NodePath path = paths;
-
- PathSentCache *psc = path_send_cache.getptr(path);
- ERR_FAIL_COND(!psc);
-
- Map<int, bool>::Element *E = psc->confirmed_peers.find(p_from);
- ERR_FAIL_COND(!E);
- E->get() = true;
- } break;
- }
-}
-
-void SceneTree::_network_poll() {
-
- if (!network_peer.is_valid() || network_peer->get_connection_status() == NetworkedMultiplayerPeer::CONNECTION_DISCONNECTED)
- return;
-
- network_peer->poll();
-
- if (!network_peer.is_valid()) //it's possible that polling might have resulted in a disconnection, so check here
- return;
-
- while (network_peer->get_available_packet_count()) {
-
- int sender = network_peer->get_packet_peer();
- const uint8_t *packet;
- int len;
-
- Error err = network_peer->get_packet(&packet, len);
- if (err != OK) {
- ERR_PRINT("Error getting packet!");
- }
-
- rpc_sender_id = sender;
- _network_process_packet(sender, packet, len);
- rpc_sender_id = 0;
-
- if (!network_peer.is_valid()) {
- break; //it's also possible that a packet or RPC caused a disconnection, so also check here
- }
- }
+ return multiplayer->is_refusing_new_network_connections();
}
void SceneTree::_bind_methods() {
@@ -2122,16 +1742,15 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_group", "name"), &SceneTree::has_group);
ClassDB::bind_method(D_METHOD("set_auto_accept_quit", "enabled"), &SceneTree::set_auto_accept_quit);
+ ClassDB::bind_method(D_METHOD("set_quit_on_go_back", "enabled"), &SceneTree::set_quit_on_go_back);
ClassDB::bind_method(D_METHOD("set_debug_collisions_hint", "enable"), &SceneTree::set_debug_collisions_hint);
ClassDB::bind_method(D_METHOD("is_debugging_collisions_hint"), &SceneTree::is_debugging_collisions_hint);
ClassDB::bind_method(D_METHOD("set_debug_navigation_hint", "enable"), &SceneTree::set_debug_navigation_hint);
ClassDB::bind_method(D_METHOD("is_debugging_navigation_hint"), &SceneTree::is_debugging_navigation_hint);
-#ifdef TOOLS_ENABLED
ClassDB::bind_method(D_METHOD("set_edited_scene_root", "scene"), &SceneTree::set_edited_scene_root);
ClassDB::bind_method(D_METHOD("get_edited_scene_root"), &SceneTree::get_edited_scene_root);
-#endif
ClassDB::bind_method(D_METHOD("set_pause", "enable"), &SceneTree::set_pause);
ClassDB::bind_method(D_METHOD("is_paused"), &SceneTree::is_paused);
@@ -2181,7 +1800,10 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene);
+ ClassDB::bind_method(D_METHOD("set_multiplayer", "multiplayer"), &SceneTree::set_multiplayer);
+ ClassDB::bind_method(D_METHOD("get_multiplayer"), &SceneTree::get_multiplayer);
ClassDB::bind_method(D_METHOD("set_network_peer", "peer"), &SceneTree::set_network_peer);
+ ClassDB::bind_method(D_METHOD("get_network_peer"), &SceneTree::get_network_peer);
ClassDB::bind_method(D_METHOD("is_network_server"), &SceneTree::is_network_server);
ClassDB::bind_method(D_METHOD("has_network_peer"), &SceneTree::has_network_peer);
ClassDB::bind_method(D_METHOD("get_network_connected_peers"), &SceneTree::get_network_connected_peers);
@@ -2195,6 +1817,20 @@ void SceneTree::_bind_methods() {
ClassDB::bind_method(D_METHOD("_connection_failed"), &SceneTree::_connection_failed);
ClassDB::bind_method(D_METHOD("_server_disconnected"), &SceneTree::_server_disconnected);
+ ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &SceneTree::set_use_font_oversampling);
+ ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &SceneTree::is_using_font_oversampling);
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_collisions_hint"), "set_debug_collisions_hint", "is_debugging_collisions_hint");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "debug_navigation_hint"), "set_debug_navigation_hint", "is_debugging_navigation_hint");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused"), "set_pause", "is_paused");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "refuse_new_network_connections"), "set_refuse_new_network_connections", "is_refusing_new_network_connections");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_font_oversampling"), "set_use_font_oversampling", "is_using_font_oversampling");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "edited_scene_root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_edited_scene_root", "get_edited_scene_root");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "current_scene", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "set_current_scene", "get_current_scene");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "network_peer", PROPERTY_HINT_RESOURCE_TYPE, "NetworkedMultiplayerPeer", 0), "set_network_peer", "get_network_peer");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "root", PROPERTY_HINT_RESOURCE_TYPE, "Node", 0), "", "get_root");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "multiplayer", PROPERTY_HINT_RESOURCE_TYPE, "MultiplayerAPI", 0), "set_multiplayer", "get_multiplayer");
+
ADD_SIGNAL(MethodInfo("tree_changed"));
ADD_SIGNAL(MethodInfo("node_added", PropertyInfo(Variant::OBJECT, "node")));
ADD_SIGNAL(MethodInfo("node_removed", PropertyInfo(Variant::OBJECT, "node")));
@@ -2244,6 +1880,20 @@ void SceneTree::add_idle_callback(IdleCallback p_callback) {
idle_callbacks[idle_callback_count++] = p_callback;
}
+void SceneTree::set_use_font_oversampling(bool p_oversampling) {
+
+ use_font_oversampling = p_oversampling;
+ if (use_font_oversampling) {
+ DynamicFontAtSize::font_oversampling = OS::get_singleton()->get_window_size().width / root->get_visible_rect().size.width;
+ } else {
+ DynamicFontAtSize::font_oversampling = 1.0;
+ }
+}
+
+bool SceneTree::is_using_font_oversampling() const {
+ return use_font_oversampling;
+}
+
SceneTree::SceneTree() {
singleton = this;
@@ -2264,9 +1914,10 @@ SceneTree::SceneTree() {
tree_version = 1;
physics_process_time = 1;
idle_process_time = 1;
- last_id = 1;
+
root = NULL;
current_frame = 0;
+ current_event = 0;
tree_changed_name = "tree_changed";
node_added_name = "node_added";
node_removed_name = "node_removed";
@@ -2274,7 +1925,6 @@ SceneTree::SceneTree() {
call_lock = 0;
root_lock = 0;
node_count = 0;
- rpc_sender_id = 0;
//create with mainloop
@@ -2283,6 +1933,9 @@ SceneTree::SceneTree() {
if (!root->get_world().is_valid())
root->set_world(Ref<World>(memnew(World)));
+ // Initialize network state
+ set_multiplayer(Ref<MultiplayerAPI>(memnew(MultiplayerAPI)));
+
//root->set_world_2d( Ref<World2D>( memnew( World2D )));
root->set_as_audio_listener(true);
root->set_as_audio_listener_2d(true);
@@ -2327,7 +1980,7 @@ SceneTree::SceneTree() {
ProjectSettings::get_singleton()->set("rendering/environment/default_environment", "");
} else {
//file was erased, notify user.
- ERR_PRINTS(RTR("Default Environment as specified in Project Setings (Rendering -> Viewport -> Default Environment) could not be loaded."));
+ ERR_PRINTS(RTR("Default Environment as specified in Project Settings (Rendering -> Environment -> Default Environment) could not be loaded."));
}
}
}
@@ -2377,9 +2030,9 @@ SceneTree::SceneTree() {
live_edit_root = NodePath("/root");
- last_send_cache_id = 1;
-
#endif
+
+ use_font_oversampling = false;
}
SceneTree::~SceneTree() {
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index 244fc8da62..6e0156546e 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,10 +27,11 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCENE_MAIN_LOOP_H
#define SCENE_MAIN_LOOP_H
-#include "io/networked_multiplayer_peer.h"
+#include "io/multiplayer_api.h"
#include "os/main_loop.h"
#include "os/thread_safe.h"
#include "scene/resources/mesh.h"
@@ -109,7 +110,6 @@ private:
float idle_process_time;
bool accept_quit;
bool quit_on_go_back;
- uint32_t last_id;
#ifdef DEBUG_ENABLED
bool debug_collisions_hint;
@@ -122,12 +122,15 @@ private:
bool _quit;
bool initialized;
bool input_handled;
+
Size2 last_screen_size;
StringName tree_changed_name;
StringName node_added_name;
StringName node_removed_name;
+ bool use_font_oversampling;
int64_t current_frame;
+ int64_t current_event;
int node_count;
#ifdef TOOLS_ENABLED
@@ -182,16 +185,8 @@ private:
///network///
- enum NetworkCommands {
- NETWORK_COMMAND_REMOTE_CALL,
- NETWORK_COMMAND_REMOTE_SET,
- NETWORK_COMMAND_SIMPLIFY_PATH,
- NETWORK_COMMAND_CONFIRM_PATH,
- };
+ Ref<MultiplayerAPI> multiplayer;
- Ref<NetworkedMultiplayerPeer> network_peer;
-
- Set<int> connected_peers;
void _network_peer_connected(int p_id);
void _network_peer_disconnected(int p_id);
@@ -199,39 +194,9 @@ private:
void _connection_failed();
void _server_disconnected();
- int rpc_sender_id;
-
- //path sent caches
- struct PathSentCache {
- Map<int, bool> confirmed_peers;
- int id;
- };
-
- HashMap<NodePath, PathSentCache> path_send_cache;
- int last_send_cache_id;
-
- //path get caches
- struct PathGetCache {
- struct NodeInfo {
- NodePath path;
- ObjectID instance;
- };
-
- Map<int, NodeInfo> nodes;
- };
-
- Map<int, PathGetCache> path_get_cache;
-
- Vector<uint8_t> packet_cache;
-
- void _network_process_packet(int p_from, const uint8_t *p_packet, int p_packet_len);
- void _network_poll();
-
static SceneTree *singleton;
friend class Node;
- void _rpc(Node *p_from, int p_to, bool p_unreliable, bool p_set, const StringName &p_name, const Variant **p_arg, int p_argcount);
-
void tree_changed();
void node_added(Node *p_node);
void node_removed(Node *p_node);
@@ -323,7 +288,7 @@ public:
NOTIFICATION_TRANSFORM_CHANGED = 29
};
- enum CallGroupFlags {
+ enum GroupCallFlags {
GROUP_CALL_DEFAULT = 0,
GROUP_CALL_REVERSE = 1,
GROUP_CALL_REALTIME = 2,
@@ -333,8 +298,6 @@ public:
_FORCE_INLINE_ Viewport *get_root() const { return root; }
- uint32_t get_last_event_id() const;
-
void call_group_flags(uint32_t p_call_flags, const StringName &p_group, const StringName &p_function, VARIANT_ARG_LIST);
void notify_group_flags(uint32_t p_call_flags, const StringName &p_group, int p_notification);
void set_group_flags(uint32_t p_call_flags, const StringName &p_group, const String &p_name, const Variant &p_value);
@@ -410,6 +373,7 @@ public:
int get_collision_debug_contact_count() { return collision_debug_contacts; }
int64_t get_frame() const;
+ int64_t get_event_count() const;
int get_node_count() const;
@@ -420,13 +384,14 @@ public:
void set_screen_stretch(StretchMode p_mode, StretchAspect p_aspect, const Size2 p_minsize, real_t p_shrink = 1);
+ void set_use_font_oversampling(bool p_oversampling);
+ bool is_using_font_oversampling() const;
+
//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
void set_current_scene(Node *p_scene);
Node *get_current_scene() const;
@@ -445,7 +410,10 @@ public:
//network API
+ Ref<MultiplayerAPI> get_multiplayer() const;
+ void set_multiplayer(Ref<MultiplayerAPI> p_multiplayer);
void set_network_peer(const Ref<NetworkedMultiplayerPeer> &p_network_peer);
+ Ref<NetworkedMultiplayerPeer> get_network_peer() const;
bool is_network_server() const;
bool has_network_peer() const;
int get_network_unique_id() const;
@@ -462,6 +430,6 @@ public:
VARIANT_ENUM_CAST(SceneTree::StretchMode);
VARIANT_ENUM_CAST(SceneTree::StretchAspect);
-VARIANT_ENUM_CAST(SceneTree::CallGroupFlags);
+VARIANT_ENUM_CAST(SceneTree::GroupCallFlags);
#endif
diff --git a/scene/main/timer.cpp b/scene/main/timer.cpp
index e0c6f93f25..c285694dfa 100755
--- a/scene/main/timer.cpp
+++ b/scene/main/timer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "timer.h"
#include "engine.h"
@@ -106,7 +107,10 @@ bool Timer::has_autostart() const {
return autostart;
}
-void Timer::start() {
+void Timer::start(float p_time) {
+ if (p_time > 0) {
+ set_wait_time(p_time);
+ }
time_left = wait_time;
_set_process(true);
}
@@ -184,7 +188,7 @@ void Timer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_autostart", "enable"), &Timer::set_autostart);
ClassDB::bind_method(D_METHOD("has_autostart"), &Timer::has_autostart);
- ClassDB::bind_method(D_METHOD("start"), &Timer::start);
+ ClassDB::bind_method(D_METHOD("start", "time_sec"), &Timer::start, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("stop"), &Timer::stop);
ClassDB::bind_method(D_METHOD("set_paused", "paused"), &Timer::set_paused);
@@ -203,6 +207,8 @@ void Timer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "wait_time", PROPERTY_HINT_EXP_RANGE, "0.01,4096,0.01"), "set_wait_time", "get_wait_time");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "one_shot"), "set_one_shot", "is_one_shot");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autostart"), "set_autostart", "has_autostart");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "paused", PROPERTY_HINT_NONE, "", 0), "set_paused", "is_paused");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "time_left", PROPERTY_HINT_NONE, "", 0), "", "get_time_left");
BIND_ENUM_CONSTANT(TIMER_PROCESS_PHYSICS);
BIND_ENUM_CONSTANT(TIMER_PROCESS_IDLE);
diff --git a/scene/main/timer.h b/scene/main/timer.h
index a02adbb0a3..2f42252a7e 100755
--- a/scene/main/timer.h
+++ b/scene/main/timer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TIMER_H
#define TIMER_H
@@ -63,7 +64,7 @@ public:
void set_autostart(bool p_start);
bool has_autostart() const;
- void start();
+ void start(float p_time = -1);
void stop();
void set_paused(bool p_paused);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 4635de81e8..f631fd6f3a 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "viewport.h"
#include "os/input.h"
@@ -71,6 +72,9 @@ void ViewportTexture::setup_local_to_scene() {
vp->viewport_textures.insert(this);
VS::get_singleton()->texture_set_proxy(proxy, vp->texture_rid);
+
+ vp->texture_flags = flags;
+ VS::get_singleton()->texture_set_flags(vp->texture_rid, flags);
}
void ViewportTexture::set_viewport_path_in_scene(const NodePath &p_path) {
@@ -121,20 +125,18 @@ Ref<Image> ViewportTexture::get_data() const {
return VS::get_singleton()->texture_get_data(vp->texture_rid);
}
void ViewportTexture::set_flags(uint32_t p_flags) {
+ flags = p_flags;
if (!vp)
return;
- vp->texture_flags = p_flags;
- VS::get_singleton()->texture_set_flags(vp->texture_rid, p_flags);
+ vp->texture_flags = flags;
+ VS::get_singleton()->texture_set_flags(vp->texture_rid, flags);
}
uint32_t ViewportTexture::get_flags() const {
- if (!vp)
- return 0;
-
- return vp->texture_flags;
+ return flags;
}
void ViewportTexture::_bind_methods() {
@@ -148,6 +150,7 @@ void ViewportTexture::_bind_methods() {
ViewportTexture::ViewportTexture() {
vp = NULL;
+ flags = 0;
set_local_to_scene(true);
proxy = VS::get_singleton()->texture_create();
}
@@ -180,24 +183,24 @@ public:
Viewport::GUI::GUI() {
mouse_focus = NULL;
+ mouse_click_grabber = NULL;
mouse_focus_button = -1;
key_focus = NULL;
mouse_over = NULL;
- cancelled_input_ID = 0;
tooltip = NULL;
tooltip_popup = NULL;
tooltip_label = NULL;
+ subwindow_visibility_dirty = false;
subwindow_order_dirty = false;
}
/////////////////////////////////////
+
void Viewport::_update_stretch_transform() {
if (size_override_stretch && size_override) {
- //print_line("sive override size "+size_override_size);
- //print_line("rect size "+size);
stretch_transform = Transform2D();
Size2 scale = size / (size_override_size + size_override_margin * 2);
stretch_transform.scale(scale);
@@ -211,114 +214,6 @@ void Viewport::_update_stretch_transform() {
_update_global_transform();
}
-void Viewport::_update_rect() {
-
- if (!is_inside_tree())
- return;
-
- /*if (!render_target && parent_control) {
-
- Control *c = parent_control;
-
- rect.pos=Point2();
- rect.size=c->get_size();
- }*/
- /*
- VisualServer::ViewportRect vr;
- vr.x=rect.pos.x;
- vr.y=rect.pos.y;
-
- if (render_target) {
- vr.x=0;
- vr.y=0;
- }
- 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);
- }
-
- emit_signal("size_changed");
- texture->emit_changed();
-*/
-}
-
-void Viewport::_parent_resized() {
-
- _update_rect();
-}
-
-void Viewport::_parent_draw() {
-}
-
-void Viewport::_parent_visibility_changed() {
-
- /*
- if (parent_control) {
-
- Control *c = parent_control;
- VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,c->is_visible_in_tree());
-
- _update_listener();
- _update_listener_2d();
- }
-*/
-}
-
-void Viewport::_vp_enter_tree() {
-
- /* if (parent_control) {
-
- Control *cparent=parent_control;
- RID parent_ci = cparent->get_canvas_item();
- ERR_FAIL_COND(!parent_ci.is_valid());
- canvas_item = VisualServer::get_singleton()->canvas_item_create();
-
- VisualServer::get_singleton()->canvas_item_set_parent(canvas_item,parent_ci);
- VisualServer::get_singleton()->canvas_item_set_visible(canvas_item,false);
- //VisualServer::get_singleton()->canvas_item_attach_viewport(canvas_item,viewport);
- parent_control->connect("resized",this,"_parent_resized");
- parent_control->connect("visibility_changed",this,"_parent_visibility_changed");
- } else if (!parent){
-
- //VisualServer::get_singleton()->viewport_attach_to_screen(viewport,0);
-
- }
-*/
-}
-
-void Viewport::_vp_exit_tree() {
-
- /*
- if (parent_control) {
-
- parent_control->disconnect("resized",this,"_parent_resized");
- }
-
- if (parent_control) {
-
- parent_control->disconnect("visibility_changed",this,"_parent_visibility_changed");
- }
-
- if (canvas_item.is_valid()) {
-
- VisualServer::get_singleton()->free(canvas_item);
- canvas_item=RID();
-
- }
-
- if (!parent) {
-
- VisualServer::get_singleton()->viewport_detach(viewport);
-
- }
-*/
-}
-
void Viewport::update_worlds() {
if (!is_inside_tree())
@@ -376,7 +271,6 @@ void Viewport::_notification(int p_what) {
_update_listener();
_update_listener_2d();
- _update_rect();
find_world_2d()->_register_viewport(this, Rect2());
@@ -429,6 +323,11 @@ void Viewport::_notification(int p_what) {
first->make_current();
}
#endif
+
+ // Enable processing for tooltips, collision debugging, physics object picking, etc.
+ set_process_internal(true);
+ set_physics_process_internal(true);
+
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -436,11 +335,6 @@ void Viewport::_notification(int p_what) {
if (world_2d.is_valid())
world_2d->_remove_viewport(this);
- /*
- if (!render_target)
- _vp_exit_tree();
- */
-
VisualServer::get_singleton()->viewport_set_scenario(viewport, RID());
// SpatialSoundServer::get_singleton()->listener_set_space(internal_listener, RID());
VisualServer::get_singleton()->viewport_remove_canvas(viewport, current_canvas);
@@ -461,15 +355,18 @@ void Viewport::_notification(int p_what) {
VS::get_singleton()->viewport_set_active(viewport, false);
} break;
- case NOTIFICATION_PHYSICS_PROCESS: {
+ case NOTIFICATION_INTERNAL_PROCESS: {
if (gui.tooltip_timer >= 0) {
- gui.tooltip_timer -= get_physics_process_delta_time();
+ gui.tooltip_timer -= get_process_delta_time();
if (gui.tooltip_timer < 0) {
_gui_show_tooltip();
}
}
+ } break;
+ case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
+
if (get_tree()->is_debugging_collisions_hint() && contact_2d_debug.is_valid()) {
VisualServer::get_singleton()->canvas_item_clear(contact_2d_debug);
@@ -679,6 +576,20 @@ void Viewport::_notification(int p_what) {
}
} break;
+ case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
+ if (gui.mouse_focus) {
+ //if mouse is being pressed, send a release event
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_position(gui.mouse_focus->get_local_mouse_position());
+ mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
+ mb->set_button_index(gui.mouse_focus_button);
+ mb->set_pressed(false);
+ Control *c = gui.mouse_focus;
+ gui.mouse_focus = NULL;
+ c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ }
+ } break;
}
}
@@ -704,7 +615,6 @@ void Viewport::set_size(const Size2 &p_size) {
size = p_size.floor();
VS::get_singleton()->viewport_set_size(viewport, size.width, size.height);
- _update_rect();
_update_stretch_transform();
emit_signal("size_changed");
@@ -1153,7 +1063,7 @@ void Viewport::set_size_override(bool p_enable, const Size2 &p_size, const Vecto
size_override_size = p_size;
}
size_override_margin = p_margin;
- _update_rect();
+
_update_stretch_transform();
emit_signal("size_changed");
}
@@ -1172,9 +1082,6 @@ void Viewport::set_size_override_stretch(bool p_enable) {
return;
size_override_stretch = p_enable;
- if (size_override) {
- _update_rect();
- }
_update_stretch_transform();
}
@@ -1347,6 +1254,24 @@ void Viewport::warp_mouse(const Vector2 &p_pos) {
Input::get_singleton()->warp_mouse_position(gpos);
}
+void Viewport::_gui_prepare_subwindows() {
+
+ if (gui.subwindow_visibility_dirty) {
+
+ gui.subwindows.clear();
+ for (List<Control *>::Element *E = gui.all_known_subwindows.front(); E; E = E->next()) {
+ if (E->get()->is_visible_in_tree()) {
+ gui.subwindows.push_back(E->get());
+ }
+ }
+
+ gui.subwindow_visibility_dirty = false;
+ gui.subwindow_order_dirty = true;
+ }
+
+ _gui_sort_subwindows();
+}
+
void Viewport::_gui_sort_subwindows() {
if (!gui.subwindow_order_dirty)
@@ -1421,8 +1346,8 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_label->set_anchor_and_margin(MARGIN_TOP, Control::ANCHOR_BEGIN, ttp->get_margin(MARGIN_TOP));
gui.tooltip_label->set_anchor_and_margin(MARGIN_RIGHT, Control::ANCHOR_END, -ttp->get_margin(MARGIN_RIGHT));
gui.tooltip_label->set_anchor_and_margin(MARGIN_BOTTOM, Control::ANCHOR_END, -ttp->get_margin(MARGIN_BOTTOM));
- gui.tooltip_label->set_text(tooltip);
- Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_combined_minimum_size() + ttp->get_minimum_size());
+ gui.tooltip_label->set_text(tooltip.strip_edges());
+ Rect2 r(gui.tooltip_pos + Point2(10, 10), gui.tooltip_label->get_minimum_size() + ttp->get_minimum_size());
Rect2 vr = gui.tooltip_label->get_viewport_rect();
if (r.size.x + r.position.x > vr.size.x)
r.position.x = vr.size.x - r.size.x;
@@ -1489,7 +1414,7 @@ void Viewport::_gui_call_input(Control *p_control, const Ref<InputEvent> &p_inpu
Control *Viewport::_gui_find_control(const Point2 &p_global) {
- _gui_sort_subwindows();
+ _gui_prepare_subwindows();
for (List<Control *>::Element *E = gui.subwindows.back(); E; E = E->prev()) {
@@ -1620,9 +1545,6 @@ bool Viewport::_gui_drop(Control *p_at_control, Point2 p_at_pos, bool p_just_che
void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
- if (p_event->get_id() == gui.cancelled_input_ID) {
- return;
- }
//?
/*
if (!is_visible()) {
@@ -1640,7 +1562,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (mb->is_pressed()) {
Size2 pos = mpos;
- if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button) {
+ if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button && mb->get_button_index() == BUTTON_LEFT) {
//do not steal mouse focus and stuff
@@ -1659,6 +1581,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
//cancel event, sorry, modal exclusive EATS UP ALL
//alternative, you can't pop out a window the same frame it was made modal (fixes many issues)
get_tree()->set_input_as_handled();
+
return; // no one gets the event if exclusive NO ONE
}
@@ -1751,7 +1674,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
_gui_call_input(gui.mouse_focus, mb);
}
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id());
get_tree()->set_input_as_handled();
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
@@ -1807,21 +1729,23 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
pos = gui.focus_inv_xform.xform(pos);
mb->set_position(pos);
- if (gui.mouse_focus->can_process()) {
- _gui_call_input(gui.mouse_focus, mb);
- }
+ Control *mouse_focus = gui.mouse_focus;
+ //disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
if (mb->get_button_index() == gui.mouse_focus_button) {
gui.mouse_focus = NULL;
gui.mouse_focus_button = -1;
}
+ if (mouse_focus->can_process()) {
+ _gui_call_input(mouse_focus, mb);
+ }
+
/*if (gui.drag_data.get_type()!=Variant::NIL && mb->get_button_index()==BUTTON_LEFT) {
_propagate_viewport_notification(this,NOTIFICATION_DRAG_END);
gui.drag_data=Variant(); //always clear
}*/
- get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "windows", "_cancel_input_ID", mb->get_id());
get_tree()->set_input_as_handled();
}
}
@@ -1911,7 +1835,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (!over) {
- OS::get_singleton()->set_cursor_shape(OS::CURSOR_ARROW);
+ OS::get_singleton()->set_cursor_shape((OS::CursorShape)Input::get_singleton()->get_default_cursor_shape());
return;
}
@@ -2032,6 +1956,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Ref<InputEventGesture> gesture_event = p_event;
if (gesture_event.is_valid()) {
+ gui.key_event_accepted = false;
+
+ _gui_cancel_tooltip();
+
Size2 pos = gesture_event->get_position();
Control *over = _gui_find_control(pos);
@@ -2122,6 +2050,9 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
top->notification(Control::NOTIFICATION_MODAL_CLOSE);
top->_modal_stack_remove();
top->hide();
+ // Close modal, set input as handled
+ get_tree()->set_input_as_handled();
+ return;
}
}
@@ -2183,8 +2114,14 @@ List<Control *>::Element *Viewport::_gui_add_root_control(Control *p_control) {
List<Control *>::Element *Viewport::_gui_add_subwindow_control(Control *p_control) {
- gui.subwindow_order_dirty = true;
- return gui.subwindows.push_back(p_control);
+ p_control->connect("visibility_changed", this, "_subwindow_visibility_changed");
+
+ if (p_control->is_visible_in_tree()) {
+ gui.subwindow_order_dirty = true;
+ gui.subwindows.push_back(p_control);
+ }
+
+ return gui.all_known_subwindows.push_back(p_control);
}
void Viewport::_gui_set_subwindow_order_dirty() {
@@ -2258,9 +2195,7 @@ void Viewport::_gui_set_drag_preview(Control *p_base, Control *p_control) {
p_control->set_position(gui.last_mouse_pos);
p_base->get_root_parent_control()->add_child(p_control); //add as child of viewport
p_control->raise();
- if (gui.drag_preview) {
- memdelete(gui.drag_preview);
- }
+
gui.drag_preview = p_control;
}
@@ -2271,7 +2206,17 @@ void Viewport::_gui_remove_root_control(List<Control *>::Element *RI) {
void Viewport::_gui_remove_subwindow_control(List<Control *>::Element *SI) {
- gui.subwindows.erase(SI);
+ ERR_FAIL_COND(!SI);
+
+ Control *control = SI->get();
+
+ control->disconnect("visibility_changed", this, "_subwindow_visibility_changed");
+
+ List<Control *>::Element *E = gui.subwindows.find(control);
+ if (E)
+ gui.subwindows.erase(E);
+
+ gui.all_known_subwindows.erase(SI);
}
void Viewport::_gui_unfocus_control(Control *p_control) {
@@ -2298,7 +2243,7 @@ void Viewport::_gui_hid_control(Control *p_control) {
*/
if (gui.key_focus == p_control)
- gui.key_focus = NULL;
+ _gui_remove_focus();
if (gui.mouse_over == p_control)
gui.mouse_over = NULL;
if (gui.tooltip == p_control)
@@ -2348,7 +2293,6 @@ void Viewport::_gui_control_grab_focus(Control *p_control) {
//no need for change
if (gui.key_focus && gui.key_focus == p_control)
return;
-
get_tree()->call_group_flags(SceneTree::GROUP_CALL_REALTIME, "_viewports", "_gui_remove_focus");
gui.key_focus = p_control;
p_control->notification(Control::NOTIFICATION_FOCUS_ENTER);
@@ -2370,6 +2314,18 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
else
p_control->_modal_set_prev_focus_owner(0);
+ if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
+ Ref<InputEventMouseButton> mb;
+ mb.instance();
+ mb->set_position(gui.mouse_focus->get_local_mouse_position());
+ mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
+ mb->set_button_index(gui.mouse_focus_button);
+ mb->set_pressed(false);
+ Control *c = gui.mouse_focus;
+ gui.mouse_focus = NULL;
+ c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
+ }
+
return gui.modal_stack.back();
}
@@ -2380,9 +2336,22 @@ Control *Viewport::_gui_get_focus_owner() {
void Viewport::_gui_grab_click_focus(Control *p_control) {
+ gui.mouse_click_grabber = p_control;
+ call_deferred("_post_gui_grab_click_focus");
+}
+
+void Viewport::_post_gui_grab_click_focus() {
+
+ Control *focus_grabber = gui.mouse_click_grabber;
+ if (!focus_grabber) {
+ // Redundant grab requests were made
+ return;
+ }
+ gui.mouse_click_grabber = NULL;
+
if (gui.mouse_focus) {
- if (gui.mouse_focus == p_control)
+ if (gui.mouse_focus == focus_grabber)
return;
Ref<InputEventMouseButton> mb;
mb.instance();
@@ -2393,9 +2362,9 @@ void Viewport::_gui_grab_click_focus(Control *p_control) {
mb->set_position(click);
mb->set_button_index(gui.mouse_focus_button);
mb->set_pressed(false);
- gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
+ gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
- gui.mouse_focus = p_control;
+ gui.mouse_focus = focus_grabber;
gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
mb->set_position(click);
@@ -2498,9 +2467,14 @@ Rect2 Viewport::get_attach_to_screen_rect() const {
void Viewport::set_physics_object_picking(bool p_enable) {
physics_object_picking = p_enable;
- set_physics_process(physics_object_picking);
- if (!physics_object_picking)
+ if (!physics_object_picking) {
physics_picking_events.clear();
+ }
+}
+
+bool Viewport::get_physics_object_picking() {
+
+ return physics_object_picking;
}
Vector2 Viewport::get_camera_coords(const Vector2 &p_viewport_coords) const {
@@ -2514,11 +2488,6 @@ Vector2 Viewport::get_camera_rect_size() const {
return size;
}
-bool Viewport::get_physics_object_picking() {
-
- return physics_object_picking;
-}
-
bool Viewport::gui_has_modal_stack() const {
return gui.modal_stack.size();
@@ -2543,6 +2512,16 @@ bool Viewport::is_3d_disabled() const {
return disable_3d;
}
+void Viewport::set_keep_3d_linear(bool p_keep_3d_linear) {
+ keep_3d_linear = p_keep_3d_linear;
+ VS::get_singleton()->viewport_set_keep_3d_linear(viewport, keep_3d_linear);
+}
+
+bool Viewport::get_keep_3d_linear() const {
+
+ return keep_3d_linear;
+}
+
Variant Viewport::gui_get_drag_data() const {
return gui.drag_data;
}
@@ -2658,9 +2637,6 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transparent_background", "enable"), &Viewport::set_transparent_background);
ClassDB::bind_method(D_METHOD("has_transparent_background"), &Viewport::has_transparent_background);
- ClassDB::bind_method(D_METHOD("_parent_visibility_changed"), &Viewport::_parent_visibility_changed);
-
- ClassDB::bind_method(D_METHOD("_parent_resized"), &Viewport::_parent_resized);
ClassDB::bind_method(D_METHOD("_vp_input"), &Viewport::_vp_input);
ClassDB::bind_method(D_METHOD("_vp_input_text", "text"), &Viewport::_vp_input_text);
ClassDB::bind_method(D_METHOD("_vp_unhandled_input"), &Viewport::_vp_unhandled_input);
@@ -2729,8 +2705,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_3d", "disable"), &Viewport::set_disable_3d);
ClassDB::bind_method(D_METHOD("is_3d_disabled"), &Viewport::is_3d_disabled);
+ ClassDB::bind_method(D_METHOD("set_keep_3d_linear", "keep_3d_linear"), &Viewport::set_keep_3d_linear);
+ ClassDB::bind_method(D_METHOD("get_keep_3d_linear"), &Viewport::get_keep_3d_linear);
+
ClassDB::bind_method(D_METHOD("_gui_show_tooltip"), &Viewport::_gui_show_tooltip);
ClassDB::bind_method(D_METHOD("_gui_remove_focus"), &Viewport::_gui_remove_focus);
+ ClassDB::bind_method(D_METHOD("_post_gui_grab_click_focus"), &Viewport::_post_gui_grab_click_focus);
ClassDB::bind_method(D_METHOD("set_shadow_atlas_size", "size"), &Viewport::set_shadow_atlas_size);
ClassDB::bind_method(D_METHOD("get_shadow_atlas_size"), &Viewport::get_shadow_atlas_size);
@@ -2741,17 +2721,20 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv);
ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv);
+ ClassDB::bind_method(D_METHOD("_subwindow_visibility_changed"), &Viewport::_subwindow_visibility_changed);
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "use_arvr");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "own_world"), "set_use_own_world", "is_using_own_world");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world", PROPERTY_HINT_RESOURCE_TYPE, "World"), "set_world", "get_world");
- //ADD_PROPERTY( PropertyInfo(Variant::OBJECT,"world_2d",PROPERTY_HINT_RESOURCE_TYPE,"World2D"), "set_world_2d", "get_world_2d") ;
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background");
ADD_GROUP("Rendering", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hdr"), "set_hdr", "get_hdr");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "disable_3d"), "set_disable_3d", "is_3d_disabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keep_3d_linear"), "set_keep_3d_linear", "get_keep_3d_linear");
ADD_PROPERTY(PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_ENUM, "2D,2D No-Sampling,3D,3D No-Effects"), "set_usage", "get_usage");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Render Target", "render_target_");
@@ -2772,6 +2755,8 @@ void Viewport::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_1", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 1);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_2", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 2);
ADD_PROPERTYI(PropertyInfo(Variant::INT, "shadow_atlas_quad_3", PROPERTY_HINT_ENUM, "Disabled,1 Shadow,4 Shadows,16 Shadows,64 Shadows,256 Shadows,1024 Shadows"), "set_shadow_atlas_quadrant_subdiv", "get_shadow_atlas_quadrant_subdiv", 3);
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_canvas_transform", "get_canvas_transform");
+ ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "global_canvas_transform", PROPERTY_HINT_NONE, "", 0), "set_global_canvas_transform", "get_global_canvas_transform");
ADD_SIGNAL(MethodInfo("size_changed"));
@@ -2818,6 +2803,13 @@ void Viewport::_bind_methods() {
BIND_ENUM_CONSTANT(CLEAR_MODE_ONLY_NEXT_FRAME);
}
+void Viewport::_subwindow_visibility_changed() {
+
+ // unfortunately, we don't know the sender, i.e. which subwindow changed;
+ // so we have to check them all.
+ gui.subwindow_visibility_dirty = true;
+}
+
Viewport::Viewport() {
world_2d = Ref<World2D>(memnew(World2D));
@@ -2872,6 +2864,7 @@ Viewport::Viewport() {
disable_input = false;
disable_3d = false;
+ keep_3d_linear = false;
//window tooltip
gui.tooltip_timer = -1;
@@ -2884,9 +2877,10 @@ Viewport::Viewport() {
gui.drag_preview = NULL;
gui.drag_attempted = false;
gui.canvas_sort_index = 0;
+ gui.roots_order_dirty = false;
msaa = MSAA_DISABLED;
- hdr = false;
+ hdr = true;
usage = USAGE_3D;
debug_draw = DEBUG_DRAW_DISABLED;
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 0835e3f69a..c1ef58de69 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -1,4 +1,3 @@
-
/*************************************************************************/
/* viewport.h */
/*************************************************************************/
@@ -6,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -28,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VIEWPORT_H
#define VIEWPORT_H
@@ -58,6 +58,7 @@ class ViewportTexture : public Texture {
friend class Viewport;
Viewport *vp;
+ uint32_t flags;
RID proxy;
@@ -206,12 +207,6 @@ private:
void _test_new_mouseover(ObjectID new_collider);
Map<ObjectID, uint64_t> physics_2d_mouseover;
- void _update_rect();
-
- void _parent_resized();
- void _parent_draw();
- void _parent_visibility_changed();
-
Ref<World2D> world_2d;
Ref<World> world;
Ref<World> own_world;
@@ -232,6 +227,7 @@ private:
void _update_global_transform();
bool disable_3d;
+ bool keep_3d_linear;
UpdateMode update_mode;
RID texture_rid;
uint32_t texture_flags;
@@ -254,6 +250,7 @@ private:
bool key_event_accepted;
Control *mouse_focus;
+ Control *mouse_click_grabber;
int mouse_focus_button;
Control *key_focus;
Control *mouse_over;
@@ -269,10 +266,11 @@ private:
float tooltip_timer;
float tooltip_delay;
List<Control *> modal_stack;
- unsigned int cancelled_input_ID;
Transform2D focus_inv_xform;
bool subwindow_order_dirty;
- List<Control *> subwindows;
+ bool subwindow_visibility_dirty;
+ List<Control *> subwindows; // visible subwindows
+ List<Control *> all_known_subwindows;
bool roots_order_dirty;
List<Control *> roots;
int canvas_sort_index; //for sorting items with canvas as root
@@ -283,6 +281,7 @@ private:
bool disable_input;
void _gui_call_input(Control *p_control, const Ref<InputEvent> &p_input);
+ void _gui_prepare_subwindows();
void _gui_sort_subwindows();
void _gui_sort_roots();
void _gui_sort_modal_stack();
@@ -295,9 +294,6 @@ private:
_FORCE_INLINE_ Transform2D _get_input_pre_xform() const;
- void _vp_enter_tree();
- void _vp_exit_tree();
-
void _vp_input(const Ref<InputEvent> &p_ev);
void _vp_input_text(const String &p_text);
void _vp_unhandled_input(const Ref<InputEvent> &p_ev);
@@ -333,6 +329,7 @@ private:
bool _gui_control_has_focus(const Control *p_control);
void _gui_control_grab_focus(Control *p_control);
void _gui_grab_click_focus(Control *p_control);
+ void _post_gui_grab_click_focus();
void _gui_accept_event();
Control *_gui_get_focus_owner();
@@ -441,6 +438,9 @@ public:
void set_disable_3d(bool p_disable);
bool is_3d_disabled() const;
+ void set_keep_3d_linear(bool p_keep_3d_linear);
+ bool get_keep_3d_linear() const;
+
void set_attach_to_screen_rect(const Rect2 &p_rect);
Rect2 get_attach_to_screen_rect() const;
@@ -471,6 +471,8 @@ public:
void set_snap_controls_to_pixels(bool p_enable);
bool is_snap_controls_to_pixels_enabled() const;
+ void _subwindow_visibility_changed();
+
Viewport();
~Viewport();
};
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 9715e1d6a0..7533fa5f6c 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "register_scene_types.h"
#include "core/class_db.h"
@@ -45,6 +46,7 @@
#include "scene/2d/light_2d.h"
#include "scene/2d/light_occluder_2d.h"
#include "scene/2d/line_2d.h"
+#include "scene/2d/mesh_instance_2d.h"
#include "scene/2d/navigation2d.h"
#include "scene/2d/parallax_background.h"
#include "scene/2d/parallax_layer.h"
@@ -56,6 +58,7 @@
#include "scene/2d/ray_cast_2d.h"
#include "scene/2d/remote_transform_2d.h"
#include "scene/2d/screen_button.h"
+#include "scene/2d/skeleton_2d.h"
#include "scene/2d/sprite.h"
#include "scene/2d/tile_map.h"
#include "scene/2d/visibility_notifier_2d.h"
@@ -200,6 +203,11 @@ static ResourceFormatLoaderDynamicFont *resource_loader_dynamic_font = NULL;
static ResourceFormatLoaderStreamTexture *resource_loader_stream_texture = NULL;
+static ResourceFormatLoaderBMFont *resource_loader_bmfont = NULL;
+
+static ResourceFormatSaverShader *resource_saver_shader = NULL;
+static ResourceFormatLoaderShader *resource_loader_shader = NULL;
+
void register_scene_types() {
SceneStringNames::create();
@@ -217,31 +225,20 @@ void register_scene_types() {
resource_loader_theme = memnew(ResourceFormatLoaderTheme);
ResourceLoader::add_resource_format_loader(resource_loader_theme);
- bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
- String theme_path = GLOBAL_DEF("gui/theme/custom", "");
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
- String font_path = GLOBAL_DEF("gui/theme/custom_font", "");
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+ resource_saver_text = memnew(ResourceFormatSaverText);
+ ResourceSaver::add_resource_format_saver(resource_saver_text, true);
- bool has_theme = false;
- if (theme_path != String()) {
- Ref<Theme> theme = ResourceLoader::load(theme_path);
- if (theme.is_valid()) {
- Theme::set_default(theme);
- has_theme = true;
- } else {
- ERR_PRINTS("Error loading custom theme '" + theme_path + "'");
- }
- }
+ resource_loader_text = memnew(ResourceFormatLoaderText);
+ ResourceLoader::add_resource_format_loader(resource_loader_text, true);
- if (!has_theme) {
- Ref<Font> font;
- if (font_path != String()) {
- font = ResourceLoader::load(font_path);
- }
- make_default_theme(default_theme_hidpi, font);
- }
+ resource_saver_shader = memnew(ResourceFormatSaverShader);
+ ResourceSaver::add_resource_format_saver(resource_saver_shader, true);
+
+ resource_loader_shader = memnew(ResourceFormatLoaderShader);
+ ResourceLoader::add_resource_format_loader(resource_loader_shader, true);
+
+ resource_loader_bmfont = memnew(ResourceFormatLoaderBMFont);
+ ResourceLoader::add_resource_format_loader(resource_loader_bmfont, true);
OS::get_singleton()->yield(); //may take time to init
@@ -268,11 +265,11 @@ void register_scene_types() {
ClassDB::register_class<Control>();
ClassDB::register_class<Button>();
ClassDB::register_class<Label>();
- ClassDB::register_class<ScrollBar>();
+ ClassDB::register_virtual_class<ScrollBar>();
ClassDB::register_class<HScrollBar>();
ClassDB::register_class<VScrollBar>();
ClassDB::register_class<ProgressBar>();
- ClassDB::register_class<Slider>();
+ ClassDB::register_virtual_class<Slider>();
ClassDB::register_class<HSlider>();
ClassDB::register_class<VSlider>();
ClassDB::register_class<Popup>();
@@ -283,7 +280,7 @@ void register_scene_types() {
ClassDB::register_class<ToolButton>();
ClassDB::register_class<LinkButton>();
ClassDB::register_class<Panel>();
- ClassDB::register_class<Range>();
+ ClassDB::register_virtual_class<Range>();
OS::get_singleton()->yield(); //may take time to init
@@ -393,6 +390,7 @@ void register_scene_types() {
ClassDB::register_class<RigidBody>();
ClassDB::register_class<KinematicCollision>();
ClassDB::register_class<KinematicBody>();
+ ClassDB::register_class<PhysicalBone>();
ClassDB::register_class<VehicleBody>();
ClassDB::register_class<VehicleWheel>();
@@ -439,6 +437,7 @@ void register_scene_types() {
ClassDB::register_class<AnimatedSprite>();
ClassDB::register_class<Position2D>();
ClassDB::register_class<Line2D>();
+ ClassDB::register_class<MeshInstance2D>();
ClassDB::register_virtual_class<CollisionObject2D>();
ClassDB::register_virtual_class<PhysicsBody2D>();
ClassDB::register_class<StaticBody2D>();
@@ -452,6 +451,8 @@ void register_scene_types() {
ClassDB::register_class<VisibilityNotifier2D>();
ClassDB::register_class<VisibilityEnabler2D>();
ClassDB::register_class<Polygon2D>();
+ ClassDB::register_class<Skeleton2D>();
+ ClassDB::register_class<Bone2D>();
ClassDB::register_class<Light2D>();
ClassDB::register_class<LightOccluder2D>();
ClassDB::register_class<OccluderPolygon2D>();
@@ -542,6 +543,8 @@ void register_scene_types() {
ClassDB::register_class<DynamicFontData>();
ClassDB::register_class<DynamicFont>();
+ DynamicFont::initialize_dynamic_fonts();
+
ClassDB::register_virtual_class<StyleBox>();
ClassDB::register_class<StyleBoxEmpty>();
ClassDB::register_class<StyleBoxTexture>();
@@ -599,18 +602,42 @@ void register_scene_types() {
OS::get_singleton()->yield(); //may take time to init
- resource_saver_text = memnew(ResourceFormatSaverText);
- ResourceSaver::add_resource_format_saver(resource_saver_text, true);
-
- resource_loader_text = memnew(ResourceFormatLoaderText);
- ResourceLoader::add_resource_format_loader(resource_loader_text, true);
-
for (int i = 0; i < 20; i++) {
GLOBAL_DEF("layer_names/2d_render/layer_" + itos(i + 1), "");
GLOBAL_DEF("layer_names/2d_physics/layer_" + itos(i + 1), "");
GLOBAL_DEF("layer_names/3d_render/layer_" + itos(i + 1), "");
GLOBAL_DEF("layer_names/3d_physics/layer_" + itos(i + 1), "");
}
+
+ bool default_theme_hidpi = GLOBAL_DEF("gui/theme/use_hidpi", false);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/use_hidpi", PropertyInfo(Variant::BOOL, "gui/theme/use_hidpi", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+ String theme_path = GLOBAL_DEF("gui/theme/custom", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+ String font_path = GLOBAL_DEF("gui/theme/custom_font", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res,*.font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ Ref<Font> font;
+ if (font_path != String()) {
+ font = ResourceLoader::load(font_path);
+ if (!font.is_valid()) {
+ ERR_PRINTS("Error loading custom font '" + font_path + "'");
+ }
+ }
+
+ // Always make the default theme to avoid invalid default font/icon/style in the given theme
+ make_default_theme(default_theme_hidpi, font);
+
+ if (theme_path != String()) {
+ Ref<Theme> theme = ResourceLoader::load(theme_path);
+ if (theme.is_valid()) {
+ Theme::set_default(theme);
+ if (font.is_valid()) {
+ Theme::set_default_font(font);
+ }
+ } else {
+ ERR_PRINTS("Error loading custom theme '" + theme_path + "'");
+ }
+ }
}
void unregister_scene_types() {
@@ -621,6 +648,8 @@ void unregister_scene_types() {
memdelete(resource_loader_stream_texture);
memdelete(resource_loader_theme);
+ DynamicFont::finish_dynamic_fonts();
+
if (resource_saver_text) {
memdelete(resource_saver_text);
}
@@ -628,6 +657,16 @@ void unregister_scene_types() {
memdelete(resource_loader_text);
}
+ if (resource_saver_shader) {
+ memdelete(resource_saver_shader);
+ }
+ if (resource_loader_shader) {
+ memdelete(resource_loader_shader);
+ }
+ if (resource_loader_bmfont) {
+ memdelete(resource_loader_bmfont);
+ }
+
SpatialMaterial::finish_shaders();
ParticlesMaterial::finish_shaders();
CanvasItemMaterial::finish_shaders();
diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h
index 956b12a7cd..9121c015fd 100644
--- a/scene/register_scene_types.h
+++ b/scene/register_scene_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef REGISTER_SCENE_TYPES_H
#define REGISTER_SCENE_TYPES_H
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 4544549f94..7a1fffaa26 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "animation.h"
#include "geometry.h"
@@ -35,13 +36,7 @@ bool Animation::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
- if (name == "length")
- set_length(p_value);
- else if (name == "loop")
- set_loop(p_value);
- else if (name == "step")
- set_step(p_value);
- else if (name.begins_with("tracks/")) {
+ if (name.begins_with("tracks/")) {
int track = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
@@ -383,20 +378,15 @@ bool Animation::_get(const StringName &p_name, Variant &r_ret) const {
}
void Animation::_get_property_list(List<PropertyInfo> *p_list) const {
-
- p_list->push_back(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"));
- p_list->push_back(PropertyInfo(Variant::BOOL, "loop"));
- p_list->push_back(PropertyInfo(Variant::REAL, "step", PROPERTY_HINT_RANGE, "0,4096,0.001"));
-
for (int i = 0; i < tracks.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::STRING, "tracks/" + itos(i) + "/type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "tracks/" + itos(i) + "/path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::INT, "tracks/" + itos(i) + "/interp", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/loop_wrap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/imported", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, "tracks/" + itos(i) + "/keys", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::STRING, "tracks/" + itos(i) + "/type", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::NODE_PATH, "tracks/" + itos(i) + "/path", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::INT, "tracks/" + itos(i) + "/interp", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/loop_wrap", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/imported", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::BOOL, "tracks/" + itos(i) + "/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, "tracks/" + itos(i) + "/keys", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
}
@@ -1613,19 +1603,19 @@ float Animation::get_step() const {
return step;
}
-void Animation::copy_track(int src_track, Ref<Animation> p_to_animation) {
+void Animation::copy_track(int p_track, Ref<Animation> p_to_animation) {
ERR_FAIL_COND(p_to_animation.is_null());
- ERR_FAIL_INDEX(src_track, get_track_count());
+ ERR_FAIL_INDEX(p_track, get_track_count());
int dst_track = p_to_animation->get_track_count();
- p_to_animation->add_track(track_get_type(src_track));
-
- p_to_animation->track_set_path(dst_track, track_get_path(src_track));
- p_to_animation->track_set_imported(dst_track, track_is_imported(src_track));
- p_to_animation->track_set_enabled(dst_track, track_is_enabled(src_track));
- p_to_animation->track_set_interpolation_type(dst_track, track_get_interpolation_type(src_track));
- p_to_animation->track_set_interpolation_loop_wrap(dst_track, track_get_interpolation_loop_wrap(src_track));
- for (int i = 0; i < track_get_key_count(src_track); i++) {
- p_to_animation->track_insert_key(dst_track, track_get_key_time(src_track, i), track_get_key_value(src_track, i), track_get_key_transition(src_track, i));
+ p_to_animation->add_track(track_get_type(p_track));
+
+ p_to_animation->track_set_path(dst_track, track_get_path(p_track));
+ p_to_animation->track_set_imported(dst_track, track_is_imported(p_track));
+ p_to_animation->track_set_enabled(dst_track, track_is_enabled(p_track));
+ p_to_animation->track_set_interpolation_type(dst_track, track_get_interpolation_type(p_track));
+ p_to_animation->track_set_interpolation_loop_wrap(dst_track, track_get_interpolation_loop_wrap(p_track));
+ for (int i = 0; i < track_get_key_count(p_track); i++) {
+ p_to_animation->track_insert_key(dst_track, track_get_key_time(p_track, i), track_get_key_value(p_track, i), track_get_key_transition(p_track, i));
}
}
@@ -1689,6 +1679,10 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &Animation::clear);
ClassDB::bind_method(D_METHOD("copy_track", "track", "to_animation"), &Animation::copy_track);
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_RANGE, "0.001,99999,0.001"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "step", PROPERTY_HINT_RANGE, "0,4096,0.001"), "set_step", "get_step");
+
BIND_ENUM_CONSTANT(TYPE_VALUE);
BIND_ENUM_CONSTANT(TYPE_TRANSFORM);
BIND_ENUM_CONSTANT(TYPE_METHOD);
diff --git a/scene/resources/animation.h b/scene/resources/animation.h
index 1f468b29b5..73691a69f2 100644
--- a/scene/resources/animation.h
+++ b/scene/resources/animation.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ANIMATION_H
#define ANIMATION_H
diff --git a/scene/resources/audio_stream_sample.cpp b/scene/resources/audio_stream_sample.cpp
index f81f460521..b77143cd9d 100644
--- a/scene/resources/audio_stream_sample.cpp
+++ b/scene/resources/audio_stream_sample.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "audio_stream_sample.h"
void AudioStreamPlaybackSample::start(float p_from_pos) {
@@ -76,7 +77,7 @@ void AudioStreamPlaybackSample::seek(float p_time) {
if (base->format == AudioStreamSample::FORMAT_IMA_ADPCM)
return; //no seeking in ima-adpcm
- float max = get_length();
+ float max = base->get_length();
if (p_time < 0) {
p_time = 0;
} else if (p_time >= max) {
@@ -389,22 +390,6 @@ void AudioStreamPlaybackSample::mix(AudioFrame *p_buffer, float p_rate_scale, in
}
}
-float AudioStreamPlaybackSample::get_length() const {
-
- int len = base->data_bytes;
- switch (base->format) {
- case AudioStreamSample::FORMAT_8_BITS: len /= 1; break;
- case AudioStreamSample::FORMAT_16_BITS: len /= 2; break;
- case AudioStreamSample::FORMAT_IMA_ADPCM: len *= 2; break;
- }
-
- if (base->stereo) {
- len /= 2;
- }
-
- return float(len) / base->mix_rate;
-}
-
AudioStreamPlaybackSample::AudioStreamPlaybackSample() {
active = false;
@@ -468,6 +453,22 @@ bool AudioStreamSample::is_stereo() const {
return stereo;
}
+float AudioStreamSample::get_length() const {
+
+ int len = data_bytes;
+ switch (format) {
+ case AudioStreamSample::FORMAT_8_BITS: len /= 1; break;
+ case AudioStreamSample::FORMAT_16_BITS: len /= 2; break;
+ case AudioStreamSample::FORMAT_IMA_ADPCM: len *= 2; break;
+ }
+
+ if (stereo) {
+ len /= 2;
+ }
+
+ return float(len) / mix_rate;
+}
+
void AudioStreamSample::set_data(const PoolVector<uint8_t> &p_data) {
AudioServer::get_singleton()->lock();
@@ -541,8 +542,8 @@ void AudioStreamSample::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stereo", "stereo"), &AudioStreamSample::set_stereo);
ClassDB::bind_method(D_METHOD("is_stereo"), &AudioStreamSample::is_stereo);
- ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamSample::set_data);
- ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamSample::get_data);
+ ClassDB::bind_method(D_METHOD("_set_data", "data"), &AudioStreamSample::set_data);
+ ClassDB::bind_method(D_METHOD("_get_data"), &AudioStreamSample::get_data);
ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format");
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_mode", PROPERTY_HINT_ENUM, "Disabled,Forward,Ping-Pong"), "set_loop_mode", "get_loop_mode");
@@ -550,7 +551,7 @@ void AudioStreamSample::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "loop_end"), "set_loop_end", "get_loop_end");
ADD_PROPERTY(PropertyInfo(Variant::INT, "mix_rate"), "set_mix_rate", "get_mix_rate");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stereo"), "set_stereo", "is_stereo");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
BIND_ENUM_CONSTANT(FORMAT_8_BITS);
BIND_ENUM_CONSTANT(FORMAT_16_BITS);
diff --git a/scene/resources/audio_stream_sample.h b/scene/resources/audio_stream_sample.h
index fbb8010a9c..5fe65c194e 100644
--- a/scene/resources/audio_stream_sample.h
+++ b/scene/resources/audio_stream_sample.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef AUDIOSTREAMSAMPLE_H
#define AUDIOSTREAMSAMPLE_H
@@ -76,8 +77,6 @@ public:
virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames);
- virtual float get_length() const; //if supported, otherwise return 0
-
AudioStreamPlaybackSample();
};
@@ -136,6 +135,8 @@ public:
void set_stereo(bool p_enable);
bool is_stereo() const;
+ virtual float get_length() const; //if supported, otherwise return 0
+
void set_data(const PoolVector<uint8_t> &p_data);
PoolVector<uint8_t> get_data() const;
diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp
index eebc872dfb..29ffefd9d6 100644
--- a/scene/resources/bit_mask.cpp
+++ b/scene/resources/bit_mask.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "bit_mask.h"
#include "io/image_loader.h"
@@ -41,7 +42,7 @@ void BitMap::create(const Size2 &p_size) {
zeromem(bitmask.ptrw(), bitmask.size());
}
-void BitMap::create_from_image_alpha(const Ref<Image> &p_image) {
+void BitMap::create_from_image_alpha(const Ref<Image> &p_image, float p_threshold) {
ERR_FAIL_COND(p_image.is_null() || p_image->empty());
Ref<Image> img = p_image->duplicate();
@@ -57,8 +58,9 @@ void BitMap::create_from_image_alpha(const Ref<Image> &p_image) {
int bbyte = i / 8;
int bbit = i % 8;
- if (r[i * 2])
+ if (r[i * 2 + 1] / 255.0 > p_threshold) {
w[bbyte] |= (1 << bbit);
+ }
}
}
@@ -80,7 +82,7 @@ void BitMap::set_bit_rect(const Rect2 &p_rect, bool p_value) {
if (p_value)
b |= (1 << bbit);
else
- b &= !(1 << bbit);
+ b &= ~(1 << bbit);
data[bbyte] = b;
}
@@ -111,8 +113,8 @@ int BitMap::get_true_bit_count() const {
void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
- int x = Math::fast_ftoi(p_pos.x);
- int y = Math::fast_ftoi(p_pos.y);
+ int x = p_pos.x;
+ int y = p_pos.y;
ERR_FAIL_INDEX(x, width);
ERR_FAIL_INDEX(y, height);
@@ -126,7 +128,7 @@ void BitMap::set_bit(const Point2 &p_pos, bool p_value) {
if (p_value)
b |= (1 << bbit);
else
- b &= !(1 << bbit);
+ b &= ~(1 << bbit);
bitmask[bbyte] = b;
}
@@ -167,10 +169,351 @@ Dictionary BitMap::_get_data() const {
return d;
}
+Vector<Vector2> BitMap::_march_square(const Rect2i &rect, const Point2i &start) const {
+
+ int stepx = 0;
+ int stepy = 0;
+ int prevx = 0;
+ int prevy = 0;
+ int startx = start.x;
+ int starty = start.y;
+ int curx = startx;
+ int cury = starty;
+ unsigned int count = 0;
+ Set<Point2i> case9s;
+ Set<Point2i> case6s;
+ int i;
+ Vector<Vector2> _points;
+ do {
+ int sv = 0;
+ { //square value
+
+ /*
+ checking the 2x2 pixel grid, assigning these values to each pixel, if not transparent
+ +---+---+
+ | 1 | 2 |
+ +---+---+
+ | 4 | 8 | <- current pixel (curx,cury)
+ +---+---+
+ */
+ //NOTE: due to the way we pick points from texture, rect needs to be smaller, otherwise it goes outside 1 pixel
+ Rect2i fixed_rect = Rect2i(rect.position, rect.size - Size2i(2, 2));
+ Point2i tl = Point2i(curx - 1, cury - 1);
+ sv += (fixed_rect.has_point(tl) && get_bit(tl)) ? 1 : 0;
+ Point2i tr = Point2i(curx, cury - 1);
+ sv += (fixed_rect.has_point(tr) && get_bit(tr)) ? 2 : 0;
+ Point2i bl = Point2i(curx - 1, cury);
+ sv += (fixed_rect.has_point(bl) && get_bit(bl)) ? 4 : 0;
+ Point2i br = Point2i(curx, cury);
+ sv += (fixed_rect.has_point(br) && get_bit(br)) ? 8 : 0;
+ ERR_FAIL_COND_V(sv == 0 || sv == 15, Vector<Vector2>());
+ }
+
+ switch (sv) {
+
+ case 1:
+ case 5:
+ case 13:
+ /* going UP with these cases:
+ 1 5 13
+ +---+---+ +---+---+ +---+---+
+ | 1 | | | 1 | | | 1 | |
+ +---+---+ +---+---+ +---+---+
+ | | | | 4 | | | 4 | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = 0;
+ stepy = -1;
+ break;
+
+ case 8:
+ case 10:
+ case 11:
+ /* going DOWN with these cases:
+ 8 10 11
+ +---+---+ +---+---+ +---+---+
+ | | | | | 2 | | 1 | 2 |
+ +---+---+ +---+---+ +---+---+
+ | | 8 | | | 8 | | | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = 0;
+ stepy = 1;
+ break;
+
+ case 4:
+ case 12:
+ case 14:
+ /* going LEFT with these cases:
+ 4 12 14
+ +---+---+ +---+---+ +---+---+
+ | | | | | | | | 2 |
+ +---+---+ +---+---+ +---+---+
+ | 4 | | | 4 | 8 | | 4 | 8 |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = -1;
+ stepy = 0;
+ break;
+
+ case 2:
+ case 3:
+ case 7:
+ /* going RIGHT with these cases:
+ 2 3 7
+ +---+---+ +---+---+ +---+---+
+ | | 2 | | 1 | 2 | | 1 | 2 |
+ +---+---+ +---+---+ +---+---+
+ | | | | | | | 4 | |
+ +---+---+ +---+---+ +---+---+
+ */
+ stepx = 1;
+ stepy = 0;
+ break;
+ case 9:
+ /*
+ +---+---+
+ | 1 | |
+ +---+---+
+ | | 8 |
+ +---+---+
+ this should normally go UP, but if we already been here, we go down
+ */
+ if (case9s.has(Point2i(curx, cury))) {
+ //found, so we go down, and delete from case9s;
+ stepx = 0;
+ stepy = 1;
+ case9s.erase(Point2i(curx, cury));
+ } else {
+ //not found, we go up, and add to case9s;
+ stepx = 0;
+ stepy = -1;
+ case9s.insert(Point2i(curx, cury));
+ }
+ break;
+ case 6:
+ /*
+ 6
+ +---+---+
+ | | 2 |
+ +---+---+
+ | 4 | |
+ +---+---+
+ this normally go RIGHT, but if its coming from UP, it should go LEFT
+ */
+ if (case6s.has(Point2i(curx, cury))) {
+ //found, so we go down, and delete from case6s;
+ stepx = -1;
+ stepy = 0;
+ case6s.erase(Point2i(curx, cury));
+ } else {
+ //not found, we go up, and add to case6s;
+ stepx = 1;
+ stepy = 0;
+ case6s.insert(Point2i(curx, cury));
+ }
+ break;
+ default:
+ ERR_PRINT("this shouldn't happen.");
+ }
+ //little optimization
+ // if previous direction is same as current direction,
+ // then we should modify the last vec to current
+ curx += stepx;
+ cury += stepy;
+ if (stepx == prevx && stepy == prevy) {
+ _points[_points.size() - 1].x = (float)(curx - rect.position.x);
+ _points[_points.size() - 1].y = (float)(cury + rect.position.y);
+ } else {
+ _points.push_back(Vector2((float)(curx - rect.position.x), (float)(cury + rect.position.y)));
+ }
+
+ count++;
+ prevx = stepx;
+ prevy = stepy;
+
+ ERR_FAIL_COND_V(count > width * height, _points);
+ } while (curx != startx || cury != starty);
+ return _points;
+}
+
+static float perpendicular_distance(const Vector2 &i, const Vector2 &start, const Vector2 &end) {
+ float res;
+ float slope;
+ float intercept;
+
+ if (start.x == end.x) {
+ res = Math::absf(i.x - end.x);
+ } else if (start.y == end.y) {
+ res = Math::absf(i.y - end.y);
+ } else {
+ slope = (end.y - start.y) / (end.x - start.x);
+ intercept = start.y - (slope * start.x);
+ res = Math::absf(slope * i.x - i.y + intercept) / Math::sqrt(Math::pow(slope, 2.0f) + 1.0);
+ }
+ return res;
+}
+
+static Vector<Vector2> rdp(const Vector<Vector2> &v, float optimization) {
+ if (v.size() < 3)
+ return v;
+
+ int index = -1;
+ float dist = 0;
+ //not looping first and last point
+ for (size_t i = 1, size = v.size(); i < size - 1; ++i) {
+ float cdist = perpendicular_distance(v[i], v[0], v[v.size() - 1]);
+ if (cdist > dist) {
+ dist = cdist;
+ index = static_cast<int>(i);
+ }
+ }
+ if (dist > optimization) {
+
+ Vector<Vector2> left, right;
+ left.resize(index);
+ for (int i = 0; i < index; i++) {
+ left[i] = v[i];
+ }
+ right.resize(v.size() - index);
+ for (int i = 0; i < right.size(); i++) {
+ right[i] = v[index + i];
+ }
+ Vector<Vector2> r1 = rdp(left, optimization);
+ Vector<Vector2> r2 = rdp(right, optimization);
+
+ int middle = r1.size();
+ r1.resize(r1.size() + r2.size());
+ for (int i = 0; i < r2.size(); i++) {
+ r1[middle + i] = r2[i];
+ }
+ return r1;
+ } else {
+ Vector<Vector2> ret;
+ ret.push_back(v[0]);
+ ret.push_back(v[v.size() - 1]);
+ return ret;
+ }
+}
+
+static Vector<Vector2> reduce(const Vector<Vector2> &points, const Rect2i &rect, float epsilon) {
+ int size = points.size();
+ // if there are less than 3 points, then we have nothing
+ ERR_FAIL_COND_V(size < 3, Vector<Vector2>());
+ // if there are less than 9 points (but more than 3), then we don't need to reduce it
+ if (size < 9) {
+ return points;
+ }
+
+ float maxEp = MIN(rect.size.width, rect.size.height);
+ float ep = CLAMP(epsilon, 0.0, maxEp / 2);
+ Vector<Vector2> result = rdp(points, ep);
+
+ Vector2 last = result[result.size() - 1];
+
+ if (last.y > result[0].y && last.distance_to(result[0]) < ep * 0.5f) {
+ result[0].y = last.y;
+ result.resize(result.size() - 1);
+ }
+ return result;
+}
+
+static void fill_bits(const BitMap *p_src, Ref<BitMap> &p_map, const Point2i &p_pos, const Rect2i &rect) {
+
+ for (int i = p_pos.x - 1; i <= p_pos.x + 1; i++) {
+ for (int j = p_pos.y - 1; j <= p_pos.y + 1; j++) {
+
+ if (i < rect.position.x || i >= rect.position.x + rect.size.x)
+ continue;
+ if (j < rect.position.y || j >= rect.position.y + rect.size.y)
+ continue;
+
+ if (p_map->get_bit(Vector2(i, j)))
+ continue;
+
+ else if (p_src->get_bit(Vector2(i, j))) {
+ p_map->set_bit(Vector2(i, j), true);
+ fill_bits(p_src, p_map, Point2i(i, j), rect);
+ }
+ }
+ }
+}
+Vector<Vector<Vector2> > BitMap::clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon) const {
+
+ Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+
+ print_line("Rect: " + r);
+ Point2i from;
+ Ref<BitMap> fill;
+ fill.instance();
+ fill->create(get_size());
+
+ Vector<Vector<Vector2> > polygons;
+ for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
+ for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
+ if (!fill->get_bit(Point2(j, i)) && get_bit(Point2(j, i))) {
+
+ Vector<Vector2> polygon = _march_square(r, Point2i(j, i));
+ print_line("pre reduce: " + itos(polygon.size()));
+ polygon = reduce(polygon, r, p_epsilon);
+ print_line("post reduce: " + itos(polygon.size()));
+ polygons.push_back(polygon);
+ fill_bits(this, fill, Point2i(j, i), r);
+ }
+ }
+ }
+
+ return polygons;
+}
+
+void BitMap::grow_mask(int p_pixels, const Rect2 &p_rect) {
+
+ Rect2i r = Rect2i(0, 0, width, height).clip(p_rect);
+
+ Ref<BitMap> copy;
+ copy.instance();
+ copy->create(get_size());
+ copy->bitmask = bitmask;
+
+ for (int i = r.position.y; i < r.position.y + r.size.height; i++) {
+ for (int j = r.position.x; j < r.position.x + r.size.width; j++) {
+ if (copy->get_bit(Point2(j, i)))
+ continue;
+
+ bool found = false;
+
+ for (int y = i - p_pixels; y <= i + p_pixels; y++) {
+ for (int x = j - p_pixels; x <= j + p_pixels; x++) {
+
+ if (x < p_rect.position.x || x >= p_rect.position.x + p_rect.size.x)
+ continue;
+ if (y < p_rect.position.y || y >= p_rect.position.y + p_rect.size.y)
+ continue;
+
+ float d = Point2(j, i).distance_to(Point2(x, y)) - CMP_EPSILON;
+ if (d > p_pixels)
+ continue;
+
+ if (copy->get_bit(Point2(x, y))) {
+ found = true;
+ break;
+ }
+ }
+ if (found)
+ break;
+ }
+
+ if (found) {
+ set_bit(Point2(j, i), true);
+ }
+ }
+ }
+}
+
void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("create", "size"), &BitMap::create);
- ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image"), &BitMap::create_from_image_alpha);
+ ClassDB::bind_method(D_METHOD("create_from_image_alpha", "image", "threshold"), &BitMap::create_from_image_alpha, DEFVAL(0.1));
ClassDB::bind_method(D_METHOD("set_bit", "position", "bit"), &BitMap::set_bit);
ClassDB::bind_method(D_METHOD("get_bit", "position"), &BitMap::get_bit);
@@ -183,7 +526,7 @@ void BitMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data"), &BitMap::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &BitMap::_get_data);
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
BitMap::BitMap() {
diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h
index 72090f2ebe..dcd5edb4fb 100644
--- a/scene/resources/bit_mask.h
+++ b/scene/resources/bit_mask.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BIT_MASK_H
#define BIT_MASK_H
@@ -38,12 +39,13 @@ class BitMap : public Resource {
GDCLASS(BitMap, Resource);
OBJ_SAVE_TYPE(BitMap);
- RES_BASE_EXTENSION("pbm");
Vector<uint8_t> bitmask;
int width;
int height;
+ Vector<Vector2> _march_square(const Rect2i &rect, const Point2i &start) const;
+
protected:
void _set_data(const Dictionary &p_d);
Dictionary _get_data() const;
@@ -52,7 +54,7 @@ protected:
public:
void create(const Size2 &p_size);
- void create_from_image_alpha(const Ref<Image> &p_image);
+ void create_from_image_alpha(const Ref<Image> &p_image, float p_threshold = 0.1);
void set_bit(const Point2 &p_pos, bool p_value);
bool get_bit(const Point2 &p_pos) const;
@@ -61,6 +63,10 @@ public:
Size2 get_size() const;
+ void grow_mask(int p_pixels, const Rect2 &p_rect);
+
+ Vector<Vector<Vector2> > clip_opaque_to_polygons(const Rect2 &p_rect, float p_epsilon = 2.0) const;
+
BitMap();
};
diff --git a/scene/resources/bounds.cpp b/scene/resources/bounds.cpp
index ee1e750c82..b115d92be3 100644
--- a/scene/resources/bounds.cpp
+++ b/scene/resources/bounds.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "bounds.h"
void Bounds::_bind_methods() {
diff --git a/scene/resources/bounds.h b/scene/resources/bounds.h
index 3378101836..dfe2fe40c6 100644
--- a/scene/resources/bounds.h
+++ b/scene/resources/bounds.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BOUNDS_H
#define BOUNDS_H
diff --git a/scene/resources/box_shape.cpp b/scene/resources/box_shape.cpp
index 858e19c9a6..e9e01ed98a 100644
--- a/scene/resources/box_shape.cpp
+++ b/scene/resources/box_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "box_shape.h"
#include "servers/physics_server.h"
diff --git a/scene/resources/box_shape.h b/scene/resources/box_shape.h
index 8884c9b75a..5ef16b4766 100644
--- a/scene/resources/box_shape.h
+++ b/scene/resources/box_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef BOX_SHAPE_H
#define BOX_SHAPE_H
diff --git a/scene/resources/canvas.cpp b/scene/resources/canvas.cpp
index f5bf0ad78e..8da1da9541 100644
--- a/scene/resources/canvas.cpp
+++ b/scene/resources/canvas.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "canvas.h"
#include "servers/visual_server.h"
diff --git a/scene/resources/canvas.h b/scene/resources/canvas.h
index b9977e11b9..dfdea82ca5 100644
--- a/scene/resources/canvas.h
+++ b/scene/resources/canvas.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CANVAS_H
#define CANVAS_H
diff --git a/scene/resources/capsule_shape.cpp b/scene/resources/capsule_shape.cpp
index f0eb8232e5..101970bad8 100644
--- a/scene/resources/capsule_shape.cpp
+++ b/scene/resources/capsule_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "capsule_shape.h"
#include "servers/physics_server.h"
diff --git a/scene/resources/capsule_shape.h b/scene/resources/capsule_shape.h
index 9b43823c83..f89d07c5f1 100644
--- a/scene/resources/capsule_shape.h
+++ b/scene/resources/capsule_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CAPSULE_SHAPE_H
#define CAPSULE_SHAPE_H
diff --git a/scene/resources/capsule_shape_2d.cpp b/scene/resources/capsule_shape_2d.cpp
index 3caf12feb8..95ab34abb2 100644
--- a/scene/resources/capsule_shape_2d.cpp
+++ b/scene/resources/capsule_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,11 +27,31 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "capsule_shape_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+Vector<Vector2> CapsuleShape2D::_get_points() const {
+
+ Vector<Vector2> points;
+ for (int i = 0; i < 24; i++) {
+ Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5);
+
+ points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs);
+ if (i == 6 || i == 18)
+ points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs);
+ }
+
+ return points;
+}
+
+bool CapsuleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, _get_points());
+}
+
void CapsuleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), Vector2(radius, height));
@@ -62,15 +82,7 @@ real_t CapsuleShape2D::get_height() const {
void CapsuleShape2D::draw(const RID &p_to_rid, const Color &p_color) {
- Vector<Vector2> points;
- for (int i = 0; i < 24; i++) {
- Vector2 ofs = Vector2(0, (i > 6 && i <= 18) ? -get_height() * 0.5 : get_height() * 0.5);
-
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() + ofs);
- if (i == 6 || i == 18)
- points.push_back(Vector2(Math::sin(i * Math_PI * 2 / 24.0), Math::cos(i * Math_PI * 2 / 24.0)) * get_radius() - ofs);
- }
-
+ Vector<Vector2> points = _get_points();
Vector<Color> col;
col.push_back(p_color);
VisualServer::get_singleton()->canvas_item_add_polygon(p_to_rid, points, col);
diff --git a/scene/resources/capsule_shape_2d.h b/scene/resources/capsule_shape_2d.h
index 610f9a4cf9..04d663c010 100644
--- a/scene/resources/capsule_shape_2d.h
+++ b/scene/resources/capsule_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CAPSULE_SHAPE_2D_H
#define CAPSULE_SHAPE_2D_H
@@ -39,11 +40,14 @@ class CapsuleShape2D : public Shape2D {
real_t radius;
void _update_shape();
+ Vector<Vector2> _get_points() const;
protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_height(real_t p_height);
real_t get_height() const;
diff --git a/scene/resources/circle_shape_2d.cpp b/scene/resources/circle_shape_2d.cpp
index bff3ed4d67..1c7bb76b26 100644
--- a/scene/resources/circle_shape_2d.cpp
+++ b/scene/resources/circle_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,10 +27,17 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "circle_shape_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+
+bool CircleShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return p_point.length() < get_radius() + p_tolerance;
+}
+
void CircleShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), radius);
diff --git a/scene/resources/circle_shape_2d.h b/scene/resources/circle_shape_2d.h
index 3ba5ec949c..06bb433170 100644
--- a/scene/resources/circle_shape_2d.h
+++ b/scene/resources/circle_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CIRCLE_SHAPE_2D_H
#define CIRCLE_SHAPE_2D_H
@@ -42,6 +43,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_radius(real_t p_radius);
real_t get_radius() const;
diff --git a/scene/resources/color_ramp.cpp b/scene/resources/color_ramp.cpp
index 9f6150ae63..b2f586d02d 100644
--- a/scene/resources/color_ramp.cpp
+++ b/scene/resources/color_ramp.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "color_ramp.h"
#include "core_string_names.h"
@@ -70,8 +71,8 @@ void Gradient::_bind_methods() {
ClassDB::bind_method(D_METHOD(COLOR_RAMP_SET_COLORS, "colors"), &Gradient::set_colors);
ClassDB::bind_method(D_METHOD(COLOR_RAMP_GET_COLORS), &Gradient::get_colors);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS);
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_REAL_ARRAY, "offsets"), COLOR_RAMP_SET_OFFSETS, COLOR_RAMP_GET_OFFSETS);
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "colors"), COLOR_RAMP_SET_COLORS, COLOR_RAMP_GET_COLORS);
}
Vector<float> Gradient::get_offsets() const {
diff --git a/scene/resources/color_ramp.h b/scene/resources/color_ramp.h
index 316c188d59..c042a0d3d0 100644
--- a/scene/resources/color_ramp.h
+++ b/scene/resources/color_ramp.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCENE_RESOURCES_COLOR_RAMP_H_
#define SCENE_RESOURCES_COLOR_RAMP_H_
diff --git a/scene/resources/concave_polygon_shape.cpp b/scene/resources/concave_polygon_shape.cpp
index 1c48f0c30b..935f041837 100644
--- a/scene/resources/concave_polygon_shape.cpp
+++ b/scene/resources/concave_polygon_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "concave_polygon_shape.h"
#include "servers/physics_server.h"
@@ -63,29 +64,6 @@ Vector<Vector3> ConcavePolygonShape::_gen_debug_mesh_lines() {
return points;
}
-bool ConcavePolygonShape::_set(const StringName &p_name, const Variant &p_value) {
-
- if (p_name == "data")
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), p_value);
- else
- return false;
-
- return true;
-}
-
-bool ConcavePolygonShape::_get(const StringName &p_name, Variant &r_ret) const {
-
- if (p_name == "data")
- r_ret = PhysicsServer::get_singleton()->shape_get_data(get_shape());
- else
- return false;
- return true;
-}
-void ConcavePolygonShape::_get_property_list(List<PropertyInfo> *p_list) const {
-
- p_list->push_back(PropertyInfo(Variant::ARRAY, "data"));
-}
-
void ConcavePolygonShape::_update_shape() {
}
@@ -104,6 +82,7 @@ void ConcavePolygonShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_faces", "faces"), &ConcavePolygonShape::set_faces);
ClassDB::bind_method(D_METHOD("get_faces"), &ConcavePolygonShape::get_faces);
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "set_faces", "get_faces");
}
ConcavePolygonShape::ConcavePolygonShape() :
diff --git a/scene/resources/concave_polygon_shape.h b/scene/resources/concave_polygon_shape.h
index 82e052fee7..2cc9095abf 100644
--- a/scene/resources/concave_polygon_shape.h
+++ b/scene/resources/concave_polygon_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CONCAVE_POLYGON_SHAPE_H
#define CONCAVE_POLYGON_SHAPE_H
@@ -57,9 +58,6 @@ class ConcavePolygonShape : public Shape {
};
protected:
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
static void _bind_methods();
virtual void _update_shape();
diff --git a/scene/resources/concave_polygon_shape_2d.cpp b/scene/resources/concave_polygon_shape_2d.cpp
index e90046fd28..d4343680ef 100644
--- a/scene/resources/concave_polygon_shape_2d.cpp
+++ b/scene/resources/concave_polygon_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,11 +27,29 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "concave_polygon_shape_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool ConcavePolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ PoolVector<Vector2> s = get_segments();
+ int len = s.size();
+ if (len == 0 || (len % 2) == 1)
+ return false;
+
+ PoolVector<Vector2>::Read r = s.read();
+ for (int i = 0; i < len; i += 2) {
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, &r[i]);
+ if (p_point.distance_to(closest) < p_tolerance)
+ return true;
+ }
+
+ return false;
+}
+
void ConcavePolygonShape2D::set_segments(const PoolVector<Vector2> &p_segments) {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), p_segments);
diff --git a/scene/resources/concave_polygon_shape_2d.h b/scene/resources/concave_polygon_shape_2d.h
index e766e88a4b..e8fa7369ac 100644
--- a/scene/resources/concave_polygon_shape_2d.h
+++ b/scene/resources/concave_polygon_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CONCAVE_POLYGON_SHAPE_2D_H
#define CONCAVE_POLYGON_SHAPE_2D_H
@@ -39,6 +40,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_segments(const PoolVector<Vector2> &p_segments);
PoolVector<Vector2> get_segments() const;
diff --git a/scene/resources/convex_polygon_shape.cpp b/scene/resources/convex_polygon_shape.cpp
index 31c4ea55e9..a2e0996996 100644
--- a/scene/resources/convex_polygon_shape.cpp
+++ b/scene/resources/convex_polygon_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "convex_polygon_shape.h"
#include "quick_hull.h"
#include "servers/physics_server.h"
diff --git a/scene/resources/convex_polygon_shape.h b/scene/resources/convex_polygon_shape.h
index e103f2d90c..62567fc031 100644
--- a/scene/resources/convex_polygon_shape.h
+++ b/scene/resources/convex_polygon_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CONVEX_POLYGON_SHAPE_H
#define CONVEX_POLYGON_SHAPE_H
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index 9c25b6b467..d061c4ea1e 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,12 +27,18 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "convex_polygon_shape_2d.h"
#include "geometry.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool ConvexPolygonShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ return Geometry::is_point_in_polygon(p_point, points);
+}
+
void ConvexPolygonShape2D::_update_shape() {
Physics2DServer::get_singleton()->shape_set_data(get_rid(), points);
diff --git a/scene/resources/convex_polygon_shape_2d.h b/scene/resources/convex_polygon_shape_2d.h
index 3354199e05..69c237a0e6 100644
--- a/scene/resources/convex_polygon_shape_2d.h
+++ b/scene/resources/convex_polygon_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CONVEX_POLYGON_SHAPE_2D_H
#define CONVEX_POLYGON_SHAPE_2D_H
@@ -42,6 +43,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_point_cloud(const Vector<Vector2> &p_points);
void set_points(const Vector<Vector2> &p_points);
Vector<Vector2> get_points() const;
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 79cc94c911..4ec1e8973d 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "curve.h"
#include "core_string_names.h"
@@ -510,7 +511,7 @@ void Curve::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::REAL, "min_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_min_value", "get_min_value");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "max_value", PROPERTY_HINT_RANGE, "-1024,1024,0.01"), "set_max_value", "get_max_value");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bake_resolution", PROPERTY_HINT_RANGE, "1,1000,1"), "set_bake_resolution", "get_bake_resolution");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
ADD_SIGNAL(MethodInfo(SIGNAL_RANGE_CHANGED));
@@ -805,6 +806,87 @@ float Curve2D::get_bake_interval() const {
return bake_interval;
}
+Vector2 Curve2D::get_closest_point(const Vector2 &p_to_point) const {
+ // Brute force method
+
+ if (baked_cache_dirty)
+ _bake();
+
+ //validate//
+ int pc = baked_point_cache.size();
+ if (pc == 0) {
+ ERR_EXPLAIN("No points in Curve2D");
+ ERR_FAIL_COND_V(pc == 0, Vector2());
+ }
+
+ if (pc == 1)
+ return baked_point_cache.get(0);
+
+ PoolVector2Array::Read r = baked_point_cache.read();
+
+ Vector2 nearest;
+ float nearest_dist = -1.0f;
+
+ for (int i = 0; i < pc - 1; i++) {
+ Vector2 origin = r[i];
+ Vector2 direction = (r[i + 1] - origin) / bake_interval;
+
+ float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval);
+ Vector2 proj = origin + direction * d;
+
+ float dist = proj.distance_squared_to(p_to_point);
+
+ if (nearest_dist < 0.0f || dist < nearest_dist) {
+ nearest = proj;
+ nearest_dist = dist;
+ }
+ }
+
+ return nearest;
+}
+
+float Curve2D::get_closest_offset(const Vector2 &p_to_point) const {
+ // Brute force method
+
+ if (baked_cache_dirty)
+ _bake();
+
+ //validate//
+ int pc = baked_point_cache.size();
+ if (pc == 0) {
+ ERR_EXPLAIN("No points in Curve2D");
+ ERR_FAIL_COND_V(pc == 0, 0.0f);
+ }
+
+ if (pc == 1)
+ return 0.0f;
+
+ PoolVector2Array::Read r = baked_point_cache.read();
+
+ float nearest = 0.0f;
+ float nearest_dist = -1.0f;
+ float offset = 0.0f;
+
+ for (int i = 0; i < pc - 1; i++) {
+ Vector2 origin = r[i];
+ Vector2 direction = (r[i + 1] - origin) / bake_interval;
+
+ float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval);
+ Vector2 proj = origin + direction * d;
+
+ float dist = proj.distance_squared_to(p_to_point);
+
+ if (nearest_dist < 0.0f || dist < nearest_dist) {
+ nearest = offset + d;
+ nearest_dist = dist;
+ }
+
+ offset += bake_interval;
+ }
+
+ return nearest;
+}
+
Dictionary Curve2D::_get_data() const {
Dictionary dc;
@@ -908,13 +990,15 @@ void Curve2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_baked_length"), &Curve2D::get_baked_length);
ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve2D::interpolate_baked, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve2D::get_baked_points);
+ ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve2D::get_closest_point);
+ ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve2D::get_closest_offset);
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve2D::tessellate, DEFVAL(5), DEFVAL(4));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve2D::_get_data);
ClassDB::bind_method(D_METHOD("_set_data"), &Curve2D::_set_data);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
Curve2D::Curve2D() {
@@ -1275,6 +1359,87 @@ PoolRealArray Curve3D::get_baked_tilts() const {
return baked_tilt_cache;
}
+Vector3 Curve3D::get_closest_point(const Vector3 &p_to_point) const {
+ // Brute force method
+
+ if (baked_cache_dirty)
+ _bake();
+
+ //validate//
+ int pc = baked_point_cache.size();
+ if (pc == 0) {
+ ERR_EXPLAIN("No points in Curve3D");
+ ERR_FAIL_COND_V(pc == 0, Vector3());
+ }
+
+ if (pc == 1)
+ return baked_point_cache.get(0);
+
+ PoolVector3Array::Read r = baked_point_cache.read();
+
+ Vector3 nearest;
+ float nearest_dist = -1.0f;
+
+ for (int i = 0; i < pc - 1; i++) {
+ Vector3 origin = r[i];
+ Vector3 direction = (r[i + 1] - origin) / bake_interval;
+
+ float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval);
+ Vector3 proj = origin + direction * d;
+
+ float dist = proj.distance_squared_to(p_to_point);
+
+ if (nearest_dist < 0.0f || dist < nearest_dist) {
+ nearest = proj;
+ nearest_dist = dist;
+ }
+ }
+
+ return nearest;
+}
+
+float Curve3D::get_closest_offset(const Vector3 &p_to_point) const {
+ // Brute force method
+
+ if (baked_cache_dirty)
+ _bake();
+
+ //validate//
+ int pc = baked_point_cache.size();
+ if (pc == 0) {
+ ERR_EXPLAIN("No points in Curve3D");
+ ERR_FAIL_COND_V(pc == 0, 0.0f);
+ }
+
+ if (pc == 1)
+ return 0.0f;
+
+ PoolVector3Array::Read r = baked_point_cache.read();
+
+ float nearest = 0.0f;
+ float nearest_dist = -1.0f;
+ float offset = 0.0f;
+
+ for (int i = 0; i < pc - 1; i++) {
+ Vector3 origin = r[i];
+ Vector3 direction = (r[i + 1] - origin) / bake_interval;
+
+ float d = CLAMP((p_to_point - origin).dot(direction), 0.0f, bake_interval);
+ Vector3 proj = origin + direction * d;
+
+ float dist = proj.distance_squared_to(p_to_point);
+
+ if (nearest_dist < 0.0f || dist < nearest_dist) {
+ nearest = offset + d;
+ nearest_dist = dist;
+ }
+
+ offset += bake_interval;
+ }
+
+ return nearest;
+}
+
void Curve3D::set_bake_interval(float p_tolerance) {
bake_interval = p_tolerance;
@@ -1403,13 +1568,15 @@ void Curve3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("interpolate_baked", "offset", "cubic"), &Curve3D::interpolate_baked, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_baked_points"), &Curve3D::get_baked_points);
ClassDB::bind_method(D_METHOD("get_baked_tilts"), &Curve3D::get_baked_tilts);
+ ClassDB::bind_method(D_METHOD("get_closest_point", "to_point"), &Curve3D::get_closest_point);
+ ClassDB::bind_method(D_METHOD("get_closest_offset", "to_point"), &Curve3D::get_closest_offset);
ClassDB::bind_method(D_METHOD("tessellate", "max_stages", "tolerance_degrees"), &Curve3D::tessellate, DEFVAL(5), DEFVAL(4));
ClassDB::bind_method(D_METHOD("_get_data"), &Curve3D::_get_data);
ClassDB::bind_method(D_METHOD("_set_data"), &Curve3D::_set_data);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "bake_interval", PROPERTY_HINT_RANGE, "0.01,512,0.01"), "set_bake_interval", "get_bake_interval");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
Curve3D::Curve3D() {
diff --git a/scene/resources/curve.h b/scene/resources/curve.h
index e7d47f4056..492eb05d1e 100644
--- a/scene/resources/curve.h
+++ b/scene/resources/curve.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef CURVE_H
#define CURVE_H
@@ -198,6 +199,8 @@ public:
float get_baked_length() const;
Vector2 interpolate_baked(float p_offset, bool p_cubic = false) const;
PoolVector2Array get_baked_points() const; //useful for going through
+ Vector2 get_closest_point(const Vector2 &p_to_point) const;
+ float get_closest_offset(const Vector2 &p_to_point) const;
PoolVector2Array tessellate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display
@@ -267,6 +270,8 @@ public:
float interpolate_baked_tilt(float p_offset) const;
PoolVector3Array get_baked_points() const; //useful for going through
PoolRealArray get_baked_tilts() const; //useful for going through
+ Vector3 get_closest_point(const Vector3 &p_to_point) const;
+ float get_closest_offset(const Vector3 &p_to_point) const;
PoolVector3Array tessellate(int p_max_stages = 5, float p_tolerance = 4) const; //useful for display
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index f4e6c5e247..3ea856541e 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -415,6 +415,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color", "Label", Color(1, 1, 1));
theme->set_color("font_color_shadow", "Label", Color(0, 0, 0, 0));
+ theme->set_color("font_outline_modulate", "Label", Color(1, 1, 1));
theme->set_constant("shadow_offset_x", "Label", 1 * scale);
theme->set_constant("shadow_offset_y", "Label", 1 * scale);
@@ -448,10 +449,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
// TextEdit
- theme->set_stylebox("normal", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3));
+ theme->set_stylebox("normal", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_stylebox("focus", "TextEdit", focus);
- theme->set_stylebox("read_only", "TextEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4));
- theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3));
+ theme->set_stylebox("read_only", "TextEdit", make_stylebox(tree_bg_disabled_png, 4, 4, 4, 4, 0, 0, 0, 0));
+ theme->set_stylebox("completion", "TextEdit", make_stylebox(tree_bg_png, 3, 3, 3, 3, 0, 0, 0, 0));
theme->set_icon("tab", "TextEdit", make_icon(tab_png));
@@ -543,6 +544,11 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("updown", "SpinBox", make_icon(spinbox_updown_png));
+ //scroll container
+ Ref<StyleBoxEmpty> empty;
+ empty.instance();
+ theme->set_stylebox("bg", "ScrollContainer", empty);
+
// WindowDialog
theme->set_stylebox("panel", "WindowDialog", sb_expand(make_stylebox(popup_window_png, 10, 26, 10, 8), 8, 24, 8, 6));
@@ -582,6 +588,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("checked", "PopupMenu", make_icon(checked_png));
theme->set_icon("unchecked", "PopupMenu", make_icon(unchecked_png));
+ theme->set_icon("radio_checked", "PopupMenu", make_icon(radio_checked_png));
+ theme->set_icon("radio_unchecked", "PopupMenu", make_icon(radio_unchecked_png));
theme->set_icon("submenu", "PopupMenu", make_icon(submenu_png));
theme->set_font("font", "PopupMenu", default_font);
@@ -816,6 +824,12 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_color_selected", "RichTextLabel", font_color_selection);
theme->set_color("selection_color", "RichTextLabel", Color(0.1, 0.1, 1, 0.8));
+ theme->set_color("font_color_shadow", "RichTextLabel", Color(0, 0, 0, 0));
+
+ theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * scale);
+ theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * scale);
+ theme->set_constant("shadow_as_outline", "RichTextLabel", 0 * scale);
+
theme->set_constant("line_separation", "RichTextLabel", 1 * scale);
theme->set_constant("table_hseparation", "RichTextLabel", 3 * scale);
theme->set_constant("table_vseparation", "RichTextLabel", 3 * scale);
@@ -880,7 +894,7 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
Ref<StyleBox> default_style;
Ref<Texture> default_icon;
- Ref<BitmapFont> default_font;
+ Ref<Font> default_font;
if (p_font.is_valid()) {
default_font = p_font;
} else if (p_hidpi) {
@@ -888,7 +902,7 @@ void make_default_theme(bool p_hidpi, Ref<Font> p_font) {
} else {
default_font = make_font2(_lodpi_font_height, _lodpi_font_ascent, _lodpi_font_charcount, &_lodpi_font_charrects[0][0], _lodpi_font_kerning_pair_count, &_lodpi_font_kerning_pairs[0][0], _lodpi_font_img_width, _lodpi_font_img_height, _lodpi_font_img_data);
}
- Ref<BitmapFont> large_font = default_font;
+ Ref<Font> large_font = default_font;
fill_default_theme(t, default_font, large_font, default_icon, default_style, p_hidpi ? 2.0 : 1.0);
Theme::set_default(t);
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index f2a4b2616d..8f211af35b 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/scene/resources/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index a40417f24d..05493d5777 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,20 +27,19 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifdef FREETYPE_ENABLED
#include "dynamic_font.h"
#include "os/file_access.h"
#include "os/os.h"
-bool DynamicFontData::CacheID::operator<(CacheID right) const {
+#include FT_STROKER_H
- if (size < right.size)
- return true;
- if (mipmaps != right.mipmaps)
- return right.mipmaps;
- if (filter != right.filter)
- return right.filter;
- return false;
+#define __STDC_LIMIT_MACROS
+#include <stdint.h>
+
+bool DynamicFontData::CacheID::operator<(CacheID right) const {
+ return key < right.key;
}
Ref<DynamicFontAtSize> DynamicFontData::_get_dynamic_font_at_size(CacheID p_cache_id) {
@@ -85,6 +84,14 @@ void DynamicFontData::set_force_autohinter(bool p_force) {
void DynamicFontData::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_font_path", "path"), &DynamicFontData::set_font_path);
ClassDB::bind_method(D_METHOD("get_font_path"), &DynamicFontData::get_font_path);
+ ClassDB::bind_method(D_METHOD("set_hinting", "mode"), &DynamicFontData::set_hinting);
+ ClassDB::bind_method(D_METHOD("get_hinting"), &DynamicFontData::get_hinting);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), "set_hinting", "get_hinting");
+
+ BIND_ENUM_CONSTANT(HINTING_NONE);
+ BIND_ENUM_CONSTANT(HINTING_LIGHT);
+ BIND_ENUM_CONSTANT(HINTING_NORMAL);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "font_path", PROPERTY_HINT_FILE, "*.ttf,*.otf"), "set_font_path", "get_font_path");
}
@@ -92,6 +99,7 @@ void DynamicFontData::_bind_methods() {
DynamicFontData::DynamicFontData() {
force_autohinter = false;
+ hinting = DynamicFontData::HINTING_NORMAL;
font_mem = NULL;
font_mem_size = 0;
}
@@ -191,10 +199,25 @@ Error DynamicFontAtSize::_load() {
ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER );
}*/
- error = FT_Set_Pixel_Sizes(face, 0, id.size);
+ if (FT_HAS_COLOR(face)) {
+ int best_match = 0;
+ int diff = ABS(id.size - face->available_sizes[0].width);
+ scale_color_font = float(id.size) / face->available_sizes[0].width;
+ for (int i = 1; i < face->num_fixed_sizes; i++) {
+ int ndiff = ABS(id.size - face->available_sizes[i].width);
+ if (ndiff < diff) {
+ best_match = i;
+ diff = ndiff;
+ scale_color_font = float(id.size) / face->available_sizes[i].width;
+ }
+ }
+ error = FT_Select_Size(face, best_match);
+ } else {
+ error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
+ }
- ascent = face->size->metrics.ascender >> 6;
- descent = -face->size->metrics.descender >> 6;
+ ascent = (face->size->metrics.ascender / 64.0) / oversampling * scale_color_font;
+ descent = (-face->size->metrics.descender / 64.0) / oversampling * scale_color_font;
linegap = 0;
texture_flags = 0;
if (id.mipmaps)
@@ -202,12 +225,12 @@ Error DynamicFontAtSize::_load() {
if (id.filter)
texture_flags |= Texture::FLAG_FILTER;
- //print_line("ASCENT: "+itos(ascent)+" descent "+itos(descent)+" hinted: "+itos(face->face_flags&FT_FACE_FLAG_HINTER));
-
valid = true;
return OK;
}
+float DynamicFontAtSize::font_oversampling = 1.0;
+
float DynamicFontAtSize::get_height() const {
return ascent + descent;
@@ -222,18 +245,11 @@ float DynamicFontAtSize::get_descent() const {
return descent;
}
-Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
+const Pair<const DynamicFontAtSize::Character *, DynamicFontAtSize *> DynamicFontAtSize::_find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
+ const Character *chr = char_map.getptr(p_char);
+ ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(NULL, NULL)));
- if (!valid)
- return Size2(1, 1);
- const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
-
- const Character *c = char_map.getptr(p_char);
- ERR_FAIL_COND_V(!c, Size2());
-
- Size2 ret(0, get_height());
-
- if (!c->found) {
+ if (!chr->found) {
//not found, try in fallbacks
for (int i = 0; i < p_fallbacks.size(); i++) {
@@ -243,52 +259,53 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V
continue;
fb->_update_char(p_char);
- const Character *ch = fb->char_map.getptr(p_char);
- ERR_CONTINUE(!ch);
+ const Character *fallback_chr = fb->char_map.getptr(p_char);
+ ERR_CONTINUE(!fallback_chr);
- if (!ch->found)
+ if (!fallback_chr->found)
continue;
- c = ch;
- break;
+ return Pair<const Character *, DynamicFontAtSize *>(fallback_chr, fb);
}
- //not found, try 0xFFFD to display 'not found'.
- if (!c->found) {
-
- const_cast<DynamicFontAtSize *>(this)->_update_char(0xFFFD);
- c = char_map.getptr(0xFFFD);
- ERR_FAIL_COND_V(!c, Size2());
- }
+ //not found, try 0xFFFD to display 'not found'.
+ const_cast<DynamicFontAtSize *>(this)->_update_char(0xFFFD);
+ chr = char_map.getptr(0xFFFD);
+ ERR_FAIL_COND_V(!chr, (Pair<const Character *, DynamicFontAtSize *>(NULL, NULL)));
}
- if (c->found) {
- ret.x = c->advance;
- }
+ return Pair<const Character *, DynamicFontAtSize *>(chr, const_cast<DynamicFontAtSize *>(this));
+}
+
+float DynamicFontAtSize::_get_kerning_advance(const DynamicFontAtSize *font, CharType p_char, CharType p_next) const {
+ float advance = 0.0;
if (p_next) {
FT_Vector delta;
- FT_Get_Kerning(face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
+ FT_Get_Kerning(font->face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
+ advance = (delta.x / 64.0) / oversampling;
+ }
- if (delta.x == 0) {
- for (int i = 0; i < p_fallbacks.size(); i++) {
+ return advance;
+}
- DynamicFontAtSize *fb = const_cast<DynamicFontAtSize *>(p_fallbacks[i].ptr());
- if (!fb->valid)
- continue;
+Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
- FT_Get_Kerning(fb->face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
+ if (!valid)
+ return Size2(1, 1);
+ const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
- if (delta.x == 0)
- continue;
+ Pair<const Character *, DynamicFontAtSize *> char_pair_with_font = _find_char_with_font(p_char, p_fallbacks);
+ const Character *ch = char_pair_with_font.first;
+ DynamicFontAtSize *font = char_pair_with_font.second;
+ ERR_FAIL_COND_V(!ch, Size2());
- ret.x += delta.x >> 6;
- break;
- }
- } else {
- ret.x += delta.x >> 6;
- }
+ Size2 ret(0, get_height());
+
+ if (ch->found) {
+ ret.x = ch->advance;
}
+ ret.x += _get_kerning_advance(font, p_char, p_next);
return ret;
}
@@ -303,92 +320,41 @@ void DynamicFontAtSize::set_texture_flags(uint32_t p_flags) {
}
}
-float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const {
+float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only) const {
if (!valid)
return 0;
const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
- const Character *c = char_map.getptr(p_char);
+ Pair<const Character *, DynamicFontAtSize *> char_pair_with_font = _find_char_with_font(p_char, p_fallbacks);
+ const Character *ch = char_pair_with_font.first;
+ DynamicFontAtSize *font = char_pair_with_font.second;
- float advance = 0;
+ ERR_FAIL_COND_V(!ch, 0.0);
- if (!c->found) {
-
- //not found, try in fallbacks
- bool used_fallback = false;
+ float advance = 0.0;
- for (int i = 0; i < p_fallbacks.size(); i++) {
-
- DynamicFontAtSize *fb = const_cast<DynamicFontAtSize *>(p_fallbacks[i].ptr());
- if (!fb->valid)
- continue;
-
- fb->_update_char(p_char);
- const Character *ch = fb->char_map.getptr(p_char);
- ERR_CONTINUE(!ch);
-
- if (!ch->found)
- continue;
+ if (ch->found) {
+ ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= font->textures.size(), 0);
+ if (!p_advance_only && ch->texture_idx != -1) {
Point2 cpos = p_pos;
cpos.x += ch->h_align;
- cpos.y -= get_ascent();
+ cpos.y -= font->get_ascent();
cpos.y += ch->v_align;
- ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= fb->textures.size(), 0);
- if (ch->texture_idx != -1)
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect, p_modulate, false, RID(), false);
- advance = ch->advance;
- used_fallback = true;
- break;
+ Color modulate = p_modulate;
+ if (FT_HAS_COLOR(face)) {
+ modulate.r = modulate.g = modulate.b = 1.0;
+ }
+ RID texture = font->textures[ch->texture_idx].texture->get_rid();
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size * Vector2(font->scale_color_font, font->scale_color_font)), texture, ch->rect_uv, modulate, false, RID(), false);
}
- //not found, try 0xFFFD to display 'not found'.
-
- if (!used_fallback) {
- const_cast<DynamicFontAtSize *>(this)->_update_char(0xFFFD);
- c = char_map.getptr(0xFFFD);
- }
+ advance = ch->advance;
}
- if (c->found) {
-
- Point2 cpos = p_pos;
- cpos.x += c->h_align;
- cpos.y -= get_ascent();
- cpos.y += c->v_align;
- ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
- if (c->texture_idx != -1)
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate, false, RID(), false);
- advance = c->advance;
- //textures[c->texture_idx].texture->draw(p_canvas_item,Vector2());
- }
-
- if (p_next) {
-
- FT_Vector delta;
- FT_Get_Kerning(face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
-
- if (delta.x == 0) {
- for (int i = 0; i < p_fallbacks.size(); i++) {
-
- DynamicFontAtSize *fb = const_cast<DynamicFontAtSize *>(p_fallbacks[i].ptr());
- if (!fb->valid)
- continue;
-
- FT_Get_Kerning(fb->face, p_char, p_next, FT_KERNING_DEFAULT, &delta);
-
- if (delta.x == 0)
- continue;
-
- advance += delta.x >> 6;
- break;
- }
- } else {
- advance += delta.x >> 6;
- }
- }
+ advance += _get_kerning_advance(font, p_char, p_next);
return advance;
}
@@ -413,79 +379,37 @@ void DynamicFontAtSize::_ft_stream_close(FT_Stream stream) {
memdelete(f);
}
-void DynamicFontAtSize::_update_char(CharType p_char) {
-
- if (char_map.has(p_char))
- return;
-
- _THREAD_SAFE_METHOD_
-
- FT_GlyphSlot slot = face->glyph;
-
- if (FT_Get_Char_Index(face, p_char) == 0) {
- //not found
- Character ch;
- ch.texture_idx = -1;
- ch.advance = 0;
- ch.h_align = 0;
- ch.v_align = 0;
- ch.found = false;
-
- char_map[p_char] = ch;
- return;
- }
- int error = FT_Load_Char(face, p_char, FT_LOAD_RENDER | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- if (!error) {
- error = FT_Render_Glyph(face->glyph, ft_render_mode_normal);
- }
- if (error) {
-
- int advance = 0;
- //stbtt_GetCodepointHMetrics(&font->info, p_char, &advance, 0);
- //print_line("char has no bitmap: "+itos(p_char)+" but advance is "+itos(advance*scale));
- Character ch;
- ch.texture_idx = -1;
- ch.advance = advance;
- ch.h_align = 0;
- ch.v_align = 0;
- ch.found = false;
-
- char_map[p_char] = ch;
-
- return;
- }
-
- int w = slot->bitmap.width;
- int h = slot->bitmap.rows;
- //int p = slot->bitmap.pitch;
- int yofs = slot->bitmap_top;
- int xofs = slot->bitmap_left;
- int advance = slot->advance.x >> 6;
-
- int mw = w + rect_margin * 2;
- int mh = h + rect_margin * 2;
-
- if (mw > 4096 || mh > 4096) {
-
- ERR_FAIL_COND(mw > 4096);
- ERR_FAIL_COND(mh > 4096);
- }
+DynamicFontAtSize::Character DynamicFontAtSize::Character::not_found() {
+ Character ch;
+ ch.texture_idx = -1;
+ ch.advance = 0;
+ ch.h_align = 0;
+ ch.v_align = 0;
+ ch.found = false;
+ return ch;
+}
- //find a texture to fit this...
+DynamicFontAtSize::TexturePosition DynamicFontAtSize::_find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height) {
+ TexturePosition ret;
+ ret.index = -1;
+ ret.x = 0;
+ ret.y = 0;
- int tex_index = -1;
- int tex_x = 0;
- int tex_y = 0;
+ int mw = p_width;
+ int mh = p_height;
for (int i = 0; i < textures.size(); i++) {
CharTexture &ct = textures[i];
+ if (ct.texture->get_format() != p_image_format)
+ continue;
+
if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture
continue;
- tex_y = 0x7FFFFFFF;
- tex_x = 0;
+ ret.y = 0x7FFFFFFF;
+ ret.x = 0;
for (int j = 0; j < ct.texture_size - mw; j++) {
@@ -498,27 +422,27 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
max_y = y;
}
- if (max_y < tex_y) {
- tex_y = max_y;
- tex_x = j;
+ if (max_y < ret.y) {
+ ret.y = max_y;
+ ret.x = j;
}
}
- if (tex_y == 0x7FFFFFFF || tex_y + mh > ct.texture_size)
+ if (ret.y == 0x7FFFFFFF || ret.y + mh > ct.texture_size)
continue; //fail, could not fit it here
- tex_index = i;
+ ret.index = i;
break;
}
//print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" X: "+itos(tex_x)+" Y: "+itos(tex_y));
- if (tex_index == -1) {
+ if (ret.index == -1) {
//could not find texture to fit, create one
- tex_x = 0;
- tex_y = 0;
+ ret.x = 0;
+ ret.y = 0;
- int texsize = MAX(id.size * 8, 256);
+ int texsize = MAX(id.size * oversampling * 8, 256);
if (mw > texsize)
texsize = mw; //special case, adapt to it?
if (mh > texsize)
@@ -530,13 +454,13 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
CharTexture tex;
tex.texture_size = texsize;
- tex.imgdata.resize(texsize * texsize * 2); //grayscale alpha
+ tex.imgdata.resize(texsize * texsize * p_color_size); //grayscale alpha
{
//zero texture
PoolVector<uint8_t>::Write w = tex.imgdata.write();
- ERR_FAIL_COND(texsize * texsize * 2 > tex.imgdata.size());
- for (int i = 0; i < texsize * texsize * 2; i++) {
+ ERR_FAIL_COND_V(texsize * texsize * p_color_size > tex.imgdata.size(), ret);
+ for (int i = 0; i < texsize * texsize * p_color_size; i++) {
w[i] = 0;
}
}
@@ -545,12 +469,31 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
tex.offsets[i] = 0;
textures.push_back(tex);
- tex_index = textures.size() - 1;
+ ret.index = textures.size() - 1;
}
+ return ret;
+}
+
+DynamicFontAtSize::Character DynamicFontAtSize::_bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance) {
+ int w = bitmap.width;
+ int h = bitmap.rows;
+
+ int mw = w + rect_margin * 2;
+ int mh = h + rect_margin * 2;
+
+ ERR_FAIL_COND_V(mw > 4096, Character::not_found());
+ ERR_FAIL_COND_V(mh > 4096, Character::not_found());
+
+ int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
+ Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
+
+ TexturePosition tex_pos = _find_texture_pos_for_glyph(color_size, require_format, mw, mh);
+ ERR_FAIL_COND_V(tex_pos.index < 0, Character::not_found());
+
//fit character in char texture
- CharTexture &tex = textures[tex_index];
+ CharTexture &tex = textures[tex_pos.index];
{
PoolVector<uint8_t>::Write wr = tex.imgdata.write();
@@ -558,23 +501,30 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_y + rect_margin) * tex.texture_size + j + tex_x + rect_margin) * 2;
- ERR_FAIL_COND(ofs >= tex.imgdata.size());
- switch (slot->bitmap.pixel_mode) {
+ int ofs = ((i + tex_pos.y + rect_margin) * tex.texture_size + j + tex_pos.x + rect_margin) * color_size;
+ ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), Character::not_found());
+ switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
- int byte = i * slot->bitmap.pitch + (j >> 3);
+ int byte = i * bitmap.pitch + (j >> 3);
int bit = 1 << (7 - (j % 8));
wr[ofs + 0] = 255; //grayscale as 1
- wr[ofs + 1] = slot->bitmap.buffer[byte] & bit ? 255 : 0;
+ wr[ofs + 1] = bitmap.buffer[byte] & bit ? 255 : 0;
} break;
case FT_PIXEL_MODE_GRAY:
wr[ofs + 0] = 255; //grayscale as 1
- wr[ofs + 1] = slot->bitmap.buffer[i * slot->bitmap.pitch + j];
+ wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
break;
- // TODO: FT_PIXEL_MODE_LCD, FT_PIXEL_MODE_BGRA
+ case FT_PIXEL_MODE_BGRA: {
+ int ofs_color = i * bitmap.pitch + (j << 2);
+ wr[ofs + 2] = bitmap.buffer[ofs_color + 0];
+ wr[ofs + 1] = bitmap.buffer[ofs_color + 1];
+ wr[ofs + 0] = bitmap.buffer[ofs_color + 2];
+ wr[ofs + 3] = bitmap.buffer[ofs_color + 3];
+ } break;
+ // TODO: FT_PIXEL_MODE_LCD
default:
- ERR_EXPLAIN("Font uses unsupported pixel format: " + itos(slot->bitmap.pixel_mode));
- ERR_FAIL();
+ ERR_EXPLAIN("Font uses unsupported pixel format: " + itos(bitmap.pixel_mode));
+ ERR_FAIL_V(Character::not_found());
break;
}
}
@@ -584,7 +534,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
//blit to image and texture
{
- Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, Image::FORMAT_LA8, tex.imgdata));
+ Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata));
if (tex.texture.is_null()) {
tex.texture.instance();
@@ -596,23 +546,112 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
// update height array
- for (int k = tex_x; k < tex_x + mw; k++) {
-
- tex.offsets[k] = tex_y + mh;
+ for (int k = tex_pos.x; k < tex_pos.x + mw; k++) {
+ tex.offsets[k] = tex_pos.y + mh;
}
Character chr;
- chr.h_align = xofs;
- chr.v_align = ascent - yofs; // + ascent - descent;
- chr.advance = advance;
- chr.texture_idx = tex_index;
+ chr.h_align = xofs * scale_color_font / oversampling;
+ chr.v_align = ascent - (yofs * scale_color_font / oversampling); // + ascent - descent;
+ chr.advance = advance * scale_color_font / oversampling;
+ chr.texture_idx = tex_pos.index;
chr.found = true;
- chr.rect = Rect2(tex_x + rect_margin, tex_y + rect_margin, w, h);
+ chr.rect_uv = Rect2(tex_pos.x + rect_margin, tex_pos.y + rect_margin, w, h);
+ chr.rect = chr.rect_uv;
+ chr.rect.position /= oversampling;
+ chr.rect.size = chr.rect.size * scale_color_font / oversampling;
+ return chr;
+}
+
+DynamicFontAtSize::Character DynamicFontAtSize::_make_outline_char(CharType p_char) {
+ Character ret = Character::not_found();
+
+ if (FT_Load_Char(face, p_char, FT_LOAD_NO_BITMAP | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0)) != 0)
+ return ret;
+
+ FT_Stroker stroker;
+ if (FT_Stroker_New(library, &stroker) != 0)
+ return ret;
+
+ FT_Stroker_Set(stroker, (int)(id.outline_size * oversampling * 64.0), FT_STROKER_LINECAP_BUTT, FT_STROKER_LINEJOIN_ROUND, 0);
+ FT_Glyph glyph;
+ FT_BitmapGlyph glyph_bitmap;
+
+ if (FT_Get_Glyph(face->glyph, &glyph) != 0)
+ goto cleanup_stroker;
+ if (FT_Glyph_Stroke(&glyph, stroker, 1) != 0)
+ goto cleanup_glyph;
+ if (FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1) != 0)
+ goto cleanup_glyph;
+
+ glyph_bitmap = (FT_BitmapGlyph)glyph;
+ ret = _bitmap_to_character(glyph_bitmap->bitmap, glyph_bitmap->top, glyph_bitmap->left, glyph->advance.x / 65536.0);
+
+cleanup_glyph:
+ FT_Done_Glyph(glyph);
+cleanup_stroker:
+ FT_Stroker_Done(stroker);
+ return ret;
+}
+
+void DynamicFontAtSize::_update_char(CharType p_char) {
+
+ if (char_map.has(p_char))
+ return;
+
+ _THREAD_SAFE_METHOD_
+
+ Character character = Character::not_found();
+
+ FT_GlyphSlot slot = face->glyph;
+
+ if (FT_Get_Char_Index(face, p_char) == 0) {
+ char_map[p_char] = character;
+ return;
+ }
+
+ int ft_hinting;
+
+ switch (font->hinting) {
+ case DynamicFontData::HINTING_NONE:
+ ft_hinting = FT_LOAD_NO_HINTING;
+ break;
+ case DynamicFontData::HINTING_LIGHT:
+ ft_hinting = FT_LOAD_TARGET_LIGHT;
+ break;
+ default:
+ ft_hinting = FT_LOAD_TARGET_NORMAL;
+ break;
+ }
+
+ int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ if (error) {
+ char_map[p_char] = character;
+ return;
+ }
- //print_line("CHAR: "+String::chr(p_char)+" TEX INDEX: "+itos(tex_index)+" RECT: "+chr.rect+" X OFS: "+itos(xofs)+" Y OFS: "+itos(yofs));
+ if (id.outline_size > 0) {
+ character = _make_outline_char(p_char);
+ } else {
+ error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+ if (!error)
+ character = _bitmap_to_character(slot->bitmap, slot->bitmap_top, slot->bitmap_left, slot->advance.x / 64.0);
+ }
- char_map[p_char] = chr;
+ char_map[p_char] = character;
+}
+
+void DynamicFontAtSize::update_oversampling() {
+ if (oversampling == font_oversampling || !valid)
+ return;
+
+ FT_Done_FreeType(library);
+ textures.clear();
+ char_map.clear();
+ oversampling = font_oversampling;
+ valid = false;
+ _load();
}
DynamicFontAtSize::DynamicFontAtSize() {
@@ -623,14 +662,17 @@ DynamicFontAtSize::DynamicFontAtSize() {
descent = 1;
linegap = 1;
texture_flags = 0;
+ oversampling = font_oversampling;
+ scale_color_font = 1;
}
DynamicFontAtSize::~DynamicFontAtSize() {
if (valid) {
FT_Done_FreeType(library);
- font->size_cache.erase(id);
}
+ font->size_cache.erase(id);
+ font.unref();
}
/////////////////////////
@@ -638,11 +680,27 @@ DynamicFontAtSize::~DynamicFontAtSize() {
void DynamicFont::_reload_cache() {
ERR_FAIL_COND(cache_id.size < 1);
- if (!data.is_valid())
+ if (!data.is_valid()) {
+ data_at_size.unref();
+ outline_data_at_size.unref();
+ fallback_data_at_size.resize(0);
+ fallback_outline_data_at_size.resize(0);
return;
+ }
+
data_at_size = data->_get_dynamic_font_at_size(cache_id);
+ if (outline_cache_id.outline_size > 0) {
+ outline_data_at_size = data->_get_dynamic_font_at_size(outline_cache_id);
+ fallback_outline_data_at_size.resize(fallback_data_at_size.size());
+ } else {
+ outline_data_at_size.unref();
+ fallback_outline_data_at_size.resize(0);
+ }
+
for (int i = 0; i < fallbacks.size(); i++) {
fallback_data_at_size[i] = fallbacks[i]->_get_dynamic_font_at_size(cache_id);
+ if (outline_cache_id.outline_size > 0)
+ fallback_outline_data_at_size[i] = fallbacks[i]->_get_dynamic_font_at_size(outline_cache_id);
}
emit_changed();
@@ -652,12 +710,10 @@ void DynamicFont::_reload_cache() {
void DynamicFont::set_font_data(const Ref<DynamicFontData> &p_data) {
data = p_data;
- if (data.is_valid())
- data_at_size = data->_get_dynamic_font_at_size(cache_id);
- else
- data_at_size = Ref<DynamicFontAtSize>();
+ _reload_cache();
emit_changed();
+ _change_notify();
}
Ref<DynamicFontData> DynamicFont::get_font_data() const {
@@ -670,6 +726,7 @@ void DynamicFont::set_size(int p_size) {
if (cache_id.size == p_size)
return;
cache_id.size = p_size;
+ outline_cache_id.size = p_size;
_reload_cache();
}
@@ -678,6 +735,30 @@ int DynamicFont::get_size() const {
return cache_id.size;
}
+void DynamicFont::set_outline_size(int p_size) {
+ if (outline_cache_id.outline_size == p_size)
+ return;
+ ERR_FAIL_COND(p_size < 0 || p_size > UINT8_MAX);
+ outline_cache_id.outline_size = p_size;
+ _reload_cache();
+}
+
+int DynamicFont::get_outline_size() const {
+ return outline_cache_id.outline_size;
+}
+
+void DynamicFont::set_outline_color(Color p_color) {
+ if (p_color != outline_color) {
+ outline_color = p_color;
+ emit_changed();
+ _change_notify();
+ }
+}
+
+Color DynamicFont::get_outline_color() const {
+ return outline_color;
+}
+
bool DynamicFont::get_use_mipmaps() const {
return cache_id.mipmaps;
@@ -688,6 +769,7 @@ void DynamicFont::set_use_mipmaps(bool p_enable) {
if (cache_id.mipmaps == p_enable)
return;
cache_id.mipmaps = p_enable;
+ outline_cache_id.mipmaps = p_enable;
_reload_cache();
}
@@ -701,9 +783,22 @@ void DynamicFont::set_use_filter(bool p_enable) {
if (cache_id.filter == p_enable)
return;
cache_id.filter = p_enable;
+ outline_cache_id.filter = p_enable;
_reload_cache();
}
+DynamicFontData::Hinting DynamicFontData::get_hinting() const {
+
+ return hinting;
+}
+
+void DynamicFontData::set_hinting(Hinting p_hinting) {
+
+ if (hinting == p_hinting)
+ return;
+ hinting = p_hinting;
+}
+
int DynamicFont::get_spacing(int p_type) const {
if (p_type == SPACING_TOP) {
@@ -778,13 +873,24 @@ bool DynamicFont::is_distance_field_hint() const {
return false;
}
-float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate) const {
+bool DynamicFont::has_outline() const {
+ return outline_cache_id.outline_size > 0;
+}
- if (!data_at_size.is_valid())
+float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
+ const Ref<DynamicFontAtSize> &font_at_size = p_outline && outline_cache_id.outline_size > 0 ? outline_data_at_size : data_at_size;
+
+ if (!font_at_size.is_valid())
return 0;
- return data_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate, fallback_data_at_size) + spacing_char;
+ const Vector<Ref<DynamicFontAtSize> > &fallbacks = p_outline && outline_cache_id.outline_size > 0 ? fallback_outline_data_at_size : fallback_data_at_size;
+ Color color = p_outline && outline_cache_id.outline_size > 0 ? p_modulate * outline_color : p_modulate;
+
+ // If requested outline draw, but no outline is present, simply return advance without drawing anything
+ bool advance_only = p_outline && outline_cache_id.outline_size == 0;
+ return font_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, color, fallbacks, advance_only) + spacing_char;
}
+
void DynamicFont::set_fallback(int p_idx, const Ref<DynamicFontData> &p_data) {
ERR_FAIL_COND(p_data.is_null());
@@ -798,6 +904,8 @@ void DynamicFont::add_fallback(const Ref<DynamicFontData> &p_data) {
ERR_FAIL_COND(p_data.is_null());
fallbacks.push_back(p_data);
fallback_data_at_size.push_back(fallbacks[fallbacks.size() - 1]->_get_dynamic_font_at_size(cache_id)); //const..
+ if (outline_cache_id.outline_size > 0)
+ fallback_outline_data_at_size.push_back(fallbacks[fallbacks.size() - 1]->_get_dynamic_font_at_size(outline_cache_id));
_change_notify();
emit_changed();
@@ -882,6 +990,12 @@ void DynamicFont::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size", "data"), &DynamicFont::set_size);
ClassDB::bind_method(D_METHOD("get_size"), &DynamicFont::get_size);
+ ClassDB::bind_method(D_METHOD("set_outline_size", "size"), &DynamicFont::set_outline_size);
+ ClassDB::bind_method(D_METHOD("get_outline_size"), &DynamicFont::get_outline_size);
+
+ ClassDB::bind_method(D_METHOD("set_outline_color", "color"), &DynamicFont::set_outline_color);
+ ClassDB::bind_method(D_METHOD("get_outline_color"), &DynamicFont::get_outline_color);
+
ClassDB::bind_method(D_METHOD("set_use_mipmaps", "enable"), &DynamicFont::set_use_mipmaps);
ClassDB::bind_method(D_METHOD("get_use_mipmaps"), &DynamicFont::get_use_mipmaps);
ClassDB::bind_method(D_METHOD("set_use_filter", "enable"), &DynamicFont::set_use_filter);
@@ -897,6 +1011,8 @@ void DynamicFont::_bind_methods() {
ADD_GROUP("Settings", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "outline_size"), "set_outline_size", "get_outline_size");
+ ADD_PROPERTY(PropertyInfo(Variant::COLOR, "outline_color"), "set_outline_color", "get_outline_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_mipmaps"), "set_use_mipmaps", "get_use_mipmaps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_filter"), "set_use_filter", "get_use_filter");
ADD_GROUP("Extra Spacing", "extra_spacing");
@@ -913,15 +1029,71 @@ void DynamicFont::_bind_methods() {
BIND_ENUM_CONSTANT(SPACING_SPACE);
}
-DynamicFont::DynamicFont() {
+Mutex *DynamicFont::dynamic_font_mutex = NULL;
+
+SelfList<DynamicFont>::List DynamicFont::dynamic_fonts;
+
+DynamicFont::DynamicFont() :
+ font_list(this) {
spacing_top = 0;
spacing_bottom = 0;
spacing_char = 0;
spacing_space = 0;
+ outline_color = Color(1, 1, 1);
+ if (dynamic_font_mutex)
+ dynamic_font_mutex->lock();
+ dynamic_fonts.add(&font_list);
+ if (dynamic_font_mutex)
+ dynamic_font_mutex->unlock();
}
DynamicFont::~DynamicFont() {
+
+ if (dynamic_font_mutex)
+ dynamic_font_mutex->lock();
+ dynamic_fonts.remove(&font_list);
+ if (dynamic_font_mutex)
+ dynamic_font_mutex->unlock();
+}
+
+void DynamicFont::initialize_dynamic_fonts() {
+ dynamic_font_mutex = Mutex::create();
+}
+
+void DynamicFont::finish_dynamic_fonts() {
+ memdelete(dynamic_font_mutex);
+ dynamic_font_mutex = NULL;
+}
+
+void DynamicFont::update_oversampling() {
+
+ Vector<Ref<DynamicFont> > changed;
+
+ if (dynamic_font_mutex)
+ dynamic_font_mutex->lock();
+
+ SelfList<DynamicFont> *E = dynamic_fonts.first();
+ while (E) {
+
+ if (E->self()->data_at_size.is_valid()) {
+ E->self()->data_at_size->update_oversampling();
+
+ if (E->self()->outline_data_at_size.is_valid()) {
+ E->self()->outline_data_at_size->update_oversampling();
+ }
+
+ changed.push_back(Ref<DynamicFont>(E->self()));
+ }
+ E = E->next();
+ }
+
+ if (dynamic_font_mutex)
+ dynamic_font_mutex->unlock();
+
+ for (int i = 0; i < changed.size(); i++) {
+ changed[i]->emit_changed();
+ }
}
/////////////////////////
diff --git a/scene/resources/dynamic_font.h b/scene/resources/dynamic_font.h
index 52c3f30590..f460bca2d4 100644
--- a/scene/resources/dynamic_font.h
+++ b/scene/resources/dynamic_font.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,12 +27,15 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef DYNAMIC_FONT_H
#define DYNAMIC_FONT_H
#ifdef FREETYPE_ENABLED
#include "io/resource_loader.h"
+#include "os/mutex.h"
#include "os/thread_safe.h"
+#include "pair.h"
#include "scene/resources/font.h"
#include <ft2build.h>
@@ -47,23 +50,35 @@ class DynamicFontData : public Resource {
public:
struct CacheID {
-
- int size;
- bool mipmaps;
- bool filter;
-
+ union {
+ struct {
+ uint32_t size : 16;
+ uint32_t outline_size : 8;
+ bool mipmaps : 1;
+ bool filter : 1;
+ };
+ uint32_t key;
+ };
bool operator<(CacheID right) const;
CacheID() {
- size = 16;
- mipmaps = false;
- filter = false;
+ key = 0;
}
};
+ enum Hinting {
+ HINTING_NONE,
+ HINTING_LIGHT,
+ HINTING_NORMAL
+ };
+
+ Hinting get_hinting() const;
+ void set_hinting(Hinting p_hinting);
+
private:
const uint8_t *font_mem;
int font_mem_size;
bool force_autohinter;
+ Hinting hinting;
String font_path;
Map<CacheID, DynamicFontAtSize *> size_cache;
@@ -87,6 +102,8 @@ public:
~DynamicFontData();
};
+VARIANT_ENUM_CAST(DynamicFontData::Hinting);
+
class DynamicFontAtSize : public Reference {
GDCLASS(DynamicFontAtSize, Reference)
@@ -97,10 +114,12 @@ class DynamicFontAtSize : public Reference {
FT_Face face; /* handle to face object */
FT_StreamRec stream;
- int ascent;
- int descent;
- int linegap;
- int rect_margin;
+ float ascent;
+ float descent;
+ float linegap;
+ float rect_margin;
+ float oversampling;
+ float scale_color_font;
uint32_t texture_flags;
@@ -121,6 +140,7 @@ class DynamicFontAtSize : public Reference {
bool found;
int texture_idx;
Rect2 rect;
+ Rect2 rect_uv;
float v_align;
float h_align;
float advance;
@@ -129,8 +149,22 @@ class DynamicFontAtSize : public Reference {
texture_idx = 0;
v_align = 0;
}
+
+ static Character not_found();
};
+ struct TexturePosition {
+ int index;
+ int x;
+ int y;
+ };
+
+ const Pair<const Character *, DynamicFontAtSize *> _find_char_with_font(CharType p_char, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const;
+ Character _make_outline_char(CharType p_char);
+ float _get_kerning_advance(const DynamicFontAtSize *font, CharType p_char, CharType p_next) const;
+ TexturePosition _find_texture_pos_for_glyph(int p_color_size, Image::Format p_image_format, int p_width, int p_height);
+ Character _bitmap_to_character(FT_Bitmap bitmap, int yofs, int xofs, float advance);
+
static unsigned long _ft_stream_io(FT_Stream stream, unsigned long offset, unsigned char *buffer, unsigned long count);
static void _ft_stream_close(FT_Stream stream);
@@ -145,8 +179,9 @@ class DynamicFontAtSize : public Reference {
static HashMap<String, Vector<uint8_t> > _fontdata;
Error _load();
-protected:
public:
+ static float font_oversampling;
+
float get_height() const;
float get_ascent() const;
@@ -154,9 +189,10 @@ public:
Size2 get_char_size(CharType p_char, CharType p_next, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const;
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks) const;
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only = false) const;
void set_texture_flags(uint32_t p_flags);
+ void update_oversampling();
DynamicFontAtSize();
~DynamicFontAtSize();
@@ -179,17 +215,23 @@ public:
private:
Ref<DynamicFontData> data;
Ref<DynamicFontAtSize> data_at_size;
+ Ref<DynamicFontAtSize> outline_data_at_size;
Vector<Ref<DynamicFontData> > fallbacks;
Vector<Ref<DynamicFontAtSize> > fallback_data_at_size;
+ Vector<Ref<DynamicFontAtSize> > fallback_outline_data_at_size;
DynamicFontData::CacheID cache_id;
+ DynamicFontData::CacheID outline_cache_id;
+
bool valid;
int spacing_top;
int spacing_bottom;
int spacing_char;
int spacing_space;
+ Color outline_color;
+
protected:
void _reload_cache();
@@ -206,6 +248,12 @@ public:
void set_size(int p_size);
int get_size() const;
+ void set_outline_size(int p_size);
+ int get_outline_size() const;
+
+ void set_outline_color(Color p_color);
+ Color get_outline_color() const;
+
bool get_use_mipmaps() const;
void set_use_mipmaps(bool p_enable);
@@ -230,7 +278,18 @@ public:
virtual bool is_distance_field_hint() const;
- virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) const;
+ virtual bool has_outline() const;
+
+ virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const;
+
+ SelfList<DynamicFont> font_list;
+
+ static Mutex *dynamic_font_mutex;
+ static SelfList<DynamicFont>::List dynamic_fonts;
+
+ static void initialize_dynamic_fonts();
+ static void finish_dynamic_fonts();
+ static void update_oversampling();
DynamicFont();
~DynamicFont();
diff --git a/scene/resources/dynamic_font_stb.cpp b/scene/resources/dynamic_font_stb.cpp
index 4aa47cb664..29f1106d16 100644
--- a/scene/resources/dynamic_font_stb.cpp
+++ b/scene/resources/dynamic_font_stb.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "dynamic_font_stb.h"
#ifndef FREETYPE_ENABLED
@@ -161,7 +162,7 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next) const {
return ret;
}
-float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate) const {
+float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
const_cast<DynamicFontAtSize *>(this)->_update_char(p_char);
@@ -171,13 +172,15 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
return 0;
}
- Point2 cpos = p_pos;
- cpos.x += c->h_align;
- cpos.y -= get_ascent();
- cpos.y += c->v_align;
- ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
- if (c->texture_idx != -1)
- VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate);
+ if (!p_outline) {
+ Point2 cpos = p_pos;
+ cpos.x += c->h_align;
+ cpos.y -= get_ascent();
+ cpos.y += c->v_align;
+ ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
+ if (c->texture_idx != -1)
+ VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect, p_modulate);
+ }
//textures[c->texture_idx].texture->draw(p_canvas_item,Vector2());
@@ -458,12 +461,12 @@ bool DynamicFont::is_distance_field_hint() const {
return false;
}
-float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate) const {
+float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
if (!data_at_size.is_valid())
return 0;
- return data_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate);
+ return data_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate, p_outline);
}
DynamicFont::DynamicFont() {
diff --git a/scene/resources/dynamic_font_stb.h b/scene/resources/dynamic_font_stb.h
index 24d764e716..feae29c0c2 100644
--- a/scene/resources/dynamic_font_stb.h
+++ b/scene/resources/dynamic_font_stb.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef DYNAMICFONT_STB_H
#define DYNAMICFONT_STB_H
@@ -135,7 +136,7 @@ public:
Size2 get_char_size(CharType p_char, CharType p_next = 0) const;
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) const;
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const;
DynamicFontAtSize();
~DynamicFontAtSize();
@@ -170,7 +171,7 @@ public:
virtual bool is_distance_field_hint() const;
- virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) const;
+ virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const;
DynamicFont();
~DynamicFont();
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index fe59450f2e..3fab4d3cfc 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "environment.h"
#include "project_settings.h"
#include "servers/visual_server.h"
@@ -269,19 +270,19 @@ void Environment::_validate_property(PropertyInfo &property) const {
if (property.name == "background_sky" || property.name == "background_sky_custom_fov" || property.name == "ambient_light/sky_contribution") {
if (bg_mode != BG_SKY && bg_mode != BG_COLOR_SKY) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
}
if (property.name == "background_color") {
if (bg_mode != BG_COLOR && bg_mode != BG_COLOR_SKY) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
}
if (property.name == "background_canvas_max_layer") {
if (bg_mode != BG_CANVAS) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
}
}
@@ -304,7 +305,7 @@ void Environment::_validate_property(PropertyInfo &property) const {
String enabled = prefix + "enabled";
if (property.name.begins_with(prefix) && property.name != enabled && !bool(get(enabled))) {
- property.usage = PROPERTY_USAGE_NOEDITOR;
+ property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
return;
}
@@ -1218,7 +1219,7 @@ Environment::Environment() {
ssao_radius2 = 0;
ssao_intensity2 = 1;
ssao_bias = 0.01;
- ssao_direct_light_affect = false;
+ ssao_direct_light_affect = 0.0;
ssao_blur = SSAO_BLUR_3x3;
set_ssao_edge_sharpness(4);
set_ssao_quality(SSAO_QUALITY_LOW);
diff --git a/scene/resources/environment.h b/scene/resources/environment.h
index 418949a6ad..27fd57aa09 100644
--- a/scene/resources/environment.h
+++ b/scene/resources/environment.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ENVIRONMENT_H
#define ENVIRONMENT_H
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index 2b44ea4554..0bae9d9b2d 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,16 +27,17 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "font.h"
#include "core/io/resource_loader.h"
#include "core/os/file_access.h"
+#include "method_bind_ext.gen.inc"
-void Font::draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate) const {
-
+void Font::draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate, const Color &p_outline_modulate) const {
float length = get_string_size(p_text).width;
if (length >= p_width) {
- draw(p_canvas_item, p_pos, p_text, p_modulate, p_width);
+ draw(p_canvas_item, p_pos, p_text, p_modulate, p_width, p_outline_modulate);
return;
}
@@ -55,13 +56,14 @@ void Font::draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, f
ERR_PRINT("Unknown halignment type");
} break;
}
- draw(p_canvas_item, p_pos + Point2(ofs, 0), p_text, p_modulate, p_width);
+ draw(p_canvas_item, p_pos + Point2(ofs, 0), p_text, p_modulate, p_width, p_outline_modulate);
}
-void Font::draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w) const {
-
+void Font::draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, const Color &p_modulate, int p_clip_w, const Color &p_outline_modulate) const {
Vector2 ofs;
+ int chars_drawn = 0;
+ bool with_outline = has_outline();
for (int i = 0; i < p_text.length(); i++) {
int width = get_char_size(p_text[i]).width;
@@ -69,7 +71,15 @@ void Font::draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, co
if (p_clip_w >= 0 && (ofs.x + width) > p_clip_w)
break; //clip
- ofs.x += draw_char(p_canvas_item, p_pos + ofs, p_text[i], p_text[i + 1], p_modulate);
+ ofs.x += draw_char(p_canvas_item, p_pos + ofs, p_text[i], p_text[i + 1], with_outline ? p_outline_modulate : p_modulate, with_outline);
+ ++chars_drawn;
+ }
+
+ if (has_outline()) {
+ ofs = Vector2(0, 0);
+ for (int i = 0; i < chars_drawn; i++) {
+ ofs.x += draw_char(p_canvas_item, p_pos + ofs, p_text[i], p_text[i + 1], p_modulate, false);
+ }
}
}
@@ -80,13 +90,14 @@ void Font::update_changes() {
void Font::_bind_methods() {
- ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "string", "modulate", "clip_w"), &Font::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("draw", "canvas_item", "position", "string", "modulate", "clip_w", "outline_modulate"), &Font::draw, DEFVAL(Color(1, 1, 1)), DEFVAL(-1), DEFVAL(Color(1, 1, 1)));
ClassDB::bind_method(D_METHOD("get_ascent"), &Font::get_ascent);
ClassDB::bind_method(D_METHOD("get_descent"), &Font::get_descent);
ClassDB::bind_method(D_METHOD("get_height"), &Font::get_height);
ClassDB::bind_method(D_METHOD("is_distance_field_hint"), &Font::is_distance_field_hint);
ClassDB::bind_method(D_METHOD("get_string_size", "string"), &Font::get_string_size);
- ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "position", "char", "next", "modulate"), &Font::draw_char, DEFVAL(-1), DEFVAL(Color(1, 1, 1)));
+ ClassDB::bind_method(D_METHOD("has_outline"), &Font::has_outline);
+ ClassDB::bind_method(D_METHOD("draw_char", "canvas_item", "position", "char", "next", "modulate", "outline"), &Font::draw_char, DEFVAL(-1), DEFVAL(Color(1, 1, 1)), DEFVAL(false));
ClassDB::bind_method(D_METHOD("update_changes"), &Font::update_changes);
}
@@ -257,8 +268,8 @@ Error BitmapFont::create_from_fnt(const String &p_file) {
if (keys.has("file")) {
- String file = keys["file"];
- file = p_file.get_base_dir() + "/" + file;
+ String base_dir = p_file.get_base_dir();
+ String file = base_dir.plus_file(keys["file"]);
Ref<Texture> tex = ResourceLoader::load(file);
if (tex.is_null()) {
ERR_PRINT("Can't load font texture!");
@@ -493,23 +504,24 @@ Ref<BitmapFont> BitmapFont::get_fallback() const {
return fallback;
}
-float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate) const {
+float BitmapFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
const Character *c = char_map.getptr(p_char);
if (!c) {
if (fallback.is_valid())
- return fallback->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate);
+ return fallback->draw_char(p_canvas_item, p_pos, p_char, p_next, p_modulate, p_outline);
return 0;
}
- Point2 cpos = p_pos;
- cpos.x += c->h_align;
- cpos.y -= ascent;
- cpos.y += c->v_align;
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
- if (c->texture_idx != -1)
+ if (!p_outline && c->texture_idx != -1) {
+ Point2 cpos = p_pos;
+ cpos.x += c->h_align;
+ cpos.y -= ascent;
+ cpos.y += c->v_align;
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx]->get_rid(), c->rect, p_modulate, false, RID(), false);
+ }
return get_char_size(p_char, p_next).width;
}
@@ -576,9 +588,9 @@ void BitmapFont::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_fallback", "fallback"), &BitmapFont::set_fallback);
ClassDB::bind_method(D_METHOD("get_fallback"), &BitmapFont::get_fallback);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_textures", "_get_textures");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "chars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_chars", "_get_chars");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "kernings", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_kernings", "_get_kernings");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "textures", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_textures", "_get_textures");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "chars", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_chars", "_get_chars");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_INT_ARRAY, "kernings", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_kernings", "_get_kernings");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "-1024,1024,1"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "ascent", PROPERTY_HINT_RANGE, "-1024,1024,1"), "set_ascent", "get_ascent");
@@ -595,3 +607,42 @@ BitmapFont::~BitmapFont() {
clear();
}
+
+////////////
+
+RES ResourceFormatLoaderBMFont::load(const String &p_path, const String &p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error = ERR_FILE_CANT_OPEN;
+
+ Ref<BitmapFont> font;
+ font.instance();
+
+ Error err = font->create_from_fnt(p_path);
+
+ if (err) {
+ if (r_error)
+ *r_error = err;
+ return RES();
+ }
+
+ return font;
+}
+
+void ResourceFormatLoaderBMFont::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("fnt");
+}
+
+bool ResourceFormatLoaderBMFont::handles_type(const String &p_type) const {
+
+ return (p_type == "BitmapFont");
+}
+
+String ResourceFormatLoaderBMFont::get_resource_type(const String &p_path) const {
+
+ String el = p_path.get_extension().to_lower();
+ if (el == "fnt")
+ return "BitmapFont";
+ return "";
+}
diff --git a/scene/resources/font.h b/scene/resources/font.h
index 3bb7aeac85..4e295b6035 100644
--- a/scene/resources/font.h
+++ b/scene/resources/font.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef FONT_H
#define FONT_H
@@ -55,14 +56,55 @@ public:
virtual bool is_distance_field_hint() const = 0;
- void draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1) const;
- void draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate = Color(1, 1, 1)) const;
- virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) const = 0;
+ void draw(RID p_canvas_item, const Point2 &p_pos, const String &p_text, const Color &p_modulate = Color(1, 1, 1), int p_clip_w = -1, const Color &p_outline_modulate = Color(1, 1, 1)) const;
+ void draw_halign(RID p_canvas_item, const Point2 &p_pos, HAlign p_align, float p_width, const String &p_text, const Color &p_modulate = Color(1, 1, 1), const Color &p_outline_modulate = Color(1, 1, 1)) const;
+
+ virtual bool has_outline() const { return false; }
+ virtual float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const = 0;
void update_changes();
Font();
};
+// Helper class to that draws outlines immediately and draws characters in its destructor.
+class FontDrawer {
+ const Ref<Font> &font;
+ Color outline_color;
+ bool has_outline;
+
+ struct PendingDraw {
+ RID canvas_item;
+ Point2 pos;
+ CharType chr;
+ CharType next;
+ Color modulate;
+ };
+
+ Vector<PendingDraw> pending_draws;
+
+public:
+ FontDrawer(const Ref<Font> &p_font, const Color &p_outline_color) :
+ font(p_font),
+ outline_color(p_outline_color) {
+ has_outline = p_font->has_outline();
+ }
+
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) {
+ if (has_outline) {
+ PendingDraw draw = { p_canvas_item, p_pos, p_char, p_next, p_modulate };
+ pending_draws.push_back(draw);
+ }
+ return font->draw_char(p_canvas_item, p_pos, p_char, p_next, has_outline ? outline_color : p_modulate, has_outline);
+ }
+
+ ~FontDrawer() {
+ for (int i = 0; i < pending_draws.size(); ++i) {
+ const PendingDraw &draw = pending_draws[i];
+ font->draw_char(draw.canvas_item, draw.pos, draw.chr, draw.next, draw.modulate, false);
+ }
+ }
+};
+
class BitmapFont : public Font {
GDCLASS(BitmapFont, Font);
@@ -152,10 +194,18 @@ public:
void set_distance_field_hint(bool p_distance_field);
bool is_distance_field_hint() const;
- float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1)) const;
+ float draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next = 0, const Color &p_modulate = Color(1, 1, 1), bool p_outline = false) const;
BitmapFont();
~BitmapFont();
};
+class ResourceFormatLoaderBMFont : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
#endif
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index 326320c60f..5e7569586a 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "material.h"
#include "scene/scene_string_names.h"
@@ -102,25 +103,19 @@ Material::~Material() {
bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
- if (p_name == SceneStringNames::get_singleton()->shader) {
- set_shader(p_value);
- return true;
- } else {
-
- if (shader.is_valid()) {
+ 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(_get_material(), pr, p_value);
- return true;
+ 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(_get_material(), pr, p_value);
+ return true;
+ }
}
return false;
@@ -128,20 +123,12 @@ bool ShaderMaterial::_set(const StringName &p_name, const Variant &p_value) {
bool ShaderMaterial::_get(const StringName &p_name, Variant &r_ret) const {
- if (p_name == SceneStringNames::get_singleton()->shader) {
-
- r_ret = get_shader();
- return true;
-
- } else {
-
- if (shader.is_valid()) {
+ if (shader.is_valid()) {
- StringName pr = shader->remap_param(p_name);
- if (pr) {
- r_ret = VisualServer::get_singleton()->material_get_param(_get_material(), pr);
- return true;
- }
+ StringName pr = shader->remap_param(p_name);
+ if (pr) {
+ r_ret = VisualServer::get_singleton()->material_get_param(_get_material(), pr);
+ return true;
}
}
@@ -150,8 +137,6 @@ 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", PROPERTY_HINT_RESOURCE_TYPE, "Shader,ShaderGraph"));
-
if (!shader.is_null()) {
shader->get_param_list(p_list);
@@ -192,6 +177,8 @@ void ShaderMaterial::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_shader"), &ShaderMaterial::get_shader);
ClassDB::bind_method(D_METHOD("set_shader_param", "param", "value"), &ShaderMaterial::set_shader_param);
ClassDB::bind_method(D_METHOD("get_shader_param", "param"), &ShaderMaterial::get_shader_param);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shader", PROPERTY_HINT_RESOURCE_TYPE, "Shader"), "set_shader", "get_shader");
}
void ShaderMaterial::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const {
@@ -400,10 +387,12 @@ void SpatialMaterial::_update_shader() {
if (flags[FLAG_USE_VERTEX_LIGHTING]) {
code += ",vertex_lighting";
}
-
if (flags[FLAG_TRIPLANAR_USE_WORLD] && (flags[FLAG_UV1_USE_TRIPLANAR] || flags[FLAG_UV2_USE_TRIPLANAR])) {
code += ",world_vertex_coords";
}
+ if (flags[FLAG_DONT_RECEIVE_SHADOWS]) {
+ code += ",shadows_disabled";
+ }
code += ";\n";
code += "uniform vec4 albedo : hint_color;\n";
@@ -563,7 +552,7 @@ void SpatialMaterial::_update_shader() {
//handle animation
code += "\tint particle_total_frames = particles_anim_h_frames * particles_anim_v_frames;\n";
- code += "\tint particle_frame = int(INSTANCE_CUSTOM.y * float(particle_total_frames));\n";
+ code += "\tint particle_frame = int(INSTANCE_CUSTOM.z * float(particle_total_frames));\n";
code += "\tif (particles_anim_loop) particle_frame=clamp(particle_frame,0,particle_total_frames-1); else particle_frame=abs(particle_frame)%particle_total_frames;\n";
code += "\tUV /= vec2(float(particles_anim_h_frames),float(particles_anim_v_frames));\n";
code += "\tUV += vec2(float(particle_frame % particles_anim_h_frames) / float(particles_anim_h_frames),float(particle_frame / particles_anim_h_frames) / float(particles_anim_v_frames));\n";
@@ -750,15 +739,18 @@ void SpatialMaterial::_update_shader() {
}
}
- if (features[FEATURE_REFRACTION] && !flags[FLAG_UV1_USE_TRIPLANAR]) { //refraction not supported with triplanar
+ if (features[FEATURE_REFRACTION]) {
if (features[FEATURE_NORMAL_MAPPING]) {
- code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) ) * SIDE;\n";
+ code += "\tvec3 ref_normal = normalize( mix(NORMAL,TANGENT * NORMALMAP.x + BINORMAL * NORMALMAP.y + NORMAL * NORMALMAP.z,NORMALMAP_DEPTH) );\n";
} else {
code += "\tvec3 ref_normal = NORMAL;\n";
}
-
- code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n";
+ if (flags[FLAG_UV1_USE_TRIPLANAR]) {
+ code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(triplanar_texture(texture_refraction,uv1_power_normal,uv1_triplanar_pos),refraction_texture_channel) * refraction;\n";
+ } else {
+ code += "\tvec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n";
+ }
code += "\tfloat ref_amount = 1.0 - albedo.a * albedo_tex.a;\n";
code += "\tEMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n";
code += "\tALBEDO *= 1.0 - ref_amount;\n";
@@ -1492,9 +1484,9 @@ bool SpatialMaterial::is_grow_enabled() const {
return grow_enabled;
}
-void SpatialMaterial::set_alpha_scissor_threshold(float p_treshold) {
- alpha_scissor_threshold = p_treshold;
- VS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_scissor_threshold, p_treshold);
+void SpatialMaterial::set_alpha_scissor_threshold(float p_threshold) {
+ alpha_scissor_threshold = p_threshold;
+ VS::get_singleton()->material_set_param(_get_material(), shader_names->alpha_scissor_threshold, p_threshold);
}
float SpatialMaterial::get_alpha_scissor_threshold() const {
@@ -1859,6 +1851,7 @@ void SpatialMaterial::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_world_triplanar"), "set_flag", "get_flag", FLAG_TRIPLANAR_USE_WORLD);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_fixed_size"), "set_flag", "get_flag", FLAG_FIXED_SIZE);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_albedo_tex_force_srgb"), "set_flag", "get_flag", FLAG_ALBEDO_TEXTURE_FORCE_SRGB);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "flags_do_not_receive_shadows"), "set_flag", "get_flag", FLAG_DONT_RECEIVE_SHADOWS);
ADD_GROUP("Vertex Color", "vertex_color");
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_use_as_albedo"), "set_flag", "get_flag", FLAG_ALBEDO_FROM_VERTEX_COLOR);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "vertex_color_is_srgb"), "set_flag", "get_flag", FLAG_SRGB_VERTEX_COLOR);
@@ -2048,6 +2041,7 @@ void SpatialMaterial::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_USE_ALPHA_SCISSOR);
BIND_ENUM_CONSTANT(FLAG_TRIPLANAR_USE_WORLD);
BIND_ENUM_CONSTANT(FLAG_ALBEDO_TEXTURE_FORCE_SRGB);
+ BIND_ENUM_CONSTANT(FLAG_DONT_RECEIVE_SHADOWS);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(DIFFUSE_BURLEY);
@@ -2140,7 +2134,7 @@ SpatialMaterial::SpatialMaterial() :
for (int i = 0; i < FLAG_MAX; i++) {
flags[i] = 0;
}
- diffuse_mode = DIFFUSE_LAMBERT;
+ diffuse_mode = DIFFUSE_BURLEY;
specular_mode = SPECULAR_SCHLICK_GGX;
for (int i = 0; i < FEATURE_MAX; i++) {
diff --git a/scene/resources/material.h b/scene/resources/material.h
index d5c3ef83e2..ce733bfb8d 100644
--- a/scene/resources/material.h
+++ b/scene/resources/material.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MATERIAL_H
#define MATERIAL_H
@@ -187,6 +188,7 @@ public:
FLAG_EMISSION_ON_UV2,
FLAG_USE_ALPHA_SCISSOR,
FLAG_ALBEDO_TEXTURE_FORCE_SRGB,
+ FLAG_DONT_RECEIVE_SHADOWS,
FLAG_MAX
};
@@ -235,7 +237,7 @@ private:
uint64_t blend_mode : 2;
uint64_t depth_draw_mode : 2;
uint64_t cull_mode : 2;
- uint64_t flags : 14;
+ uint64_t flags : 15;
uint64_t detail_blend_mode : 2;
uint64_t diffuse_mode : 3;
uint64_t specular_mode : 2;
@@ -565,7 +567,7 @@ public:
void set_grow(float p_grow);
float get_grow() const;
- void set_alpha_scissor_threshold(float p_treshold);
+ void set_alpha_scissor_threshold(float p_threshold);
float get_alpha_scissor_threshold() const;
void set_on_top_of_alpha();
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index bb33962be6..b0620d3363 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "mesh.h"
#include "pair.h"
@@ -221,7 +222,6 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
continue;
Array a = surface_get_arrays(i);
- int vcount = 0;
if (i == 0) {
arrays = a;
@@ -229,6 +229,7 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
index_accum += v.size();
} else {
+ int vcount = 0;
for (int j = 0; j < arrays.size(); j++) {
if (arrays[j].get_type() == Variant::NIL || a[j].get_type() == Variant::NIL) {
@@ -314,6 +315,8 @@ Ref<Mesh> Mesh::create_outline(float p_margin) const {
}
}
+ ERR_FAIL_COND_V(arrays.size() != ARRAY_MAX, Ref<ArrayMesh>());
+
{
PoolVector<int>::Write ir;
PoolVector<int> indices = arrays[ARRAY_INDEX];
@@ -558,12 +561,6 @@ bool ArrayMesh::_set(const StringName &p_name, const Variant &p_value) {
return true;
}
- if (sname == "custom_aabb/custom_aabb") {
-
- set_custom_aabb(p_value);
- return true;
- }
-
if (!sname.begins_with("surfaces"))
return false;
@@ -672,11 +669,6 @@ bool ArrayMesh::_get(const StringName &p_name, Variant &r_ret) const {
else if (what == "name")
r_ret = surface_get_name(idx);
return true;
- } else if (sname == "custom_aabb/custom_aabb") {
-
- r_ret = custom_aabb;
- return true;
-
} else if (!sname.begins_with("surfaces"))
return false;
@@ -727,13 +719,13 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
return;
if (blend_shapes.size()) {
- p_list->push_back(PropertyInfo(Variant::POOL_STRING_ARRAY, "blend_shape/names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::POOL_STRING_ARRAY, "blend_shape/names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::INT, "blend_shape/mode", PROPERTY_HINT_ENUM, "Normalized,Relative"));
}
for (int i = 0; i < surfaces.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::DICTIONARY, "surfaces/" + itos(i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::DICTIONARY, "surfaces/" + itos(i), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
p_list->push_back(PropertyInfo(Variant::STRING, "surface_" + itos(i + 1) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
if (surfaces[i].is_2d) {
p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,CanvasItemMaterial", PROPERTY_USAGE_EDITOR));
@@ -741,8 +733,6 @@ void ArrayMesh::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, "surface_" + itos(i + 1) + "/material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial,SpatialMaterial", PROPERTY_USAGE_EDITOR));
}
}
-
- p_list->push_back(PropertyInfo(Variant::AABB, "custom_aabb/custom_aabb"));
}
void ArrayMesh::_recompute_aabb() {
@@ -922,6 +912,7 @@ void ArrayMesh::surface_set_material(int p_idx, const Ref<Material> &p_material)
VisualServer::get_singleton()->mesh_surface_set_material(mesh, p_idx, p_material.is_null() ? RID() : p_material->get_rid());
_change_notify("material");
+ emit_changed();
}
void ArrayMesh::surface_set_name(int p_idx, const String &p_name) {
@@ -929,6 +920,7 @@ void ArrayMesh::surface_set_name(int p_idx, const String &p_name) {
ERR_FAIL_INDEX(p_idx, surfaces.size());
surfaces[p_idx].name = p_name;
+ emit_changed();
}
String ArrayMesh::surface_get_name(int p_idx) const {
@@ -941,6 +933,7 @@ void ArrayMesh::surface_update_region(int p_surface, int p_offset, const PoolVec
ERR_FAIL_INDEX(p_surface, surfaces.size());
VS::get_singleton()->mesh_surface_update_region(mesh, p_surface, p_offset, p_data);
+ emit_changed();
}
void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) {
@@ -948,6 +941,7 @@ void ArrayMesh::surface_set_custom_aabb(int p_idx, const AABB &p_aabb) {
ERR_FAIL_INDEX(p_idx, surfaces.size());
surfaces[p_idx].aabb = p_aabb;
// set custom aabb too?
+ emit_changed();
}
Ref<Material> ArrayMesh::surface_get_material(int p_idx) const {
@@ -996,6 +990,7 @@ void ArrayMesh::set_custom_aabb(const AABB &p_custom) {
custom_aabb = p_custom;
VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
+ emit_changed();
}
AABB ArrayMesh::get_custom_aabb() const {
@@ -1111,13 +1106,14 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
for (int j = 0; j < vc; j++) {
Vector3 v = p_base_transform.xform(r[j]);
+ Vector3 n = p_base_transform.basis.xform(rn[j]).normalized();
vertices[(j + vertex_ofs) * 3 + 0] = v.x;
vertices[(j + vertex_ofs) * 3 + 1] = v.y;
vertices[(j + vertex_ofs) * 3 + 2] = v.z;
- normals[(j + vertex_ofs) * 3 + 0] = rn[j].x;
- normals[(j + vertex_ofs) * 3 + 1] = rn[j].y;
- normals[(j + vertex_ofs) * 3 + 2] = rn[j].z;
+ normals[(j + vertex_ofs) * 3 + 0] = n.x;
+ normals[(j + vertex_ofs) * 3 + 1] = n.y;
+ normals[(j + vertex_ofs) * 3 + 2] = n.z;
uv_index[j + vertex_ofs] = Pair<int, int>(i, j);
}
@@ -1198,8 +1194,6 @@ Error ArrayMesh::lightmap_unwrap(const Transform &p_base_transform, float p_texe
for (int j = 0; j < 3; j++) {
- int vertex_idx = gen_vertices[gen_indices[i + j]];
-
SurfaceTool::Vertex v = surfaces[surface].vertices[uv_index[gen_vertices[gen_indices[i + j]]].second];
if (surfaces[surface].format & ARRAY_FORMAT_COLOR) {
@@ -1278,12 +1272,17 @@ void ArrayMesh::_bind_methods() {
ClassDB::set_method_flags(get_class_static(), _scs_create("center_geometry"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ClassDB::bind_method(D_METHOD("regen_normalmaps"), &ArrayMesh::regen_normalmaps);
ClassDB::set_method_flags(get_class_static(), _scs_create("regen_normalmaps"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
+ ClassDB::bind_method(D_METHOD("lightmap_unwrap"), &ArrayMesh::lightmap_unwrap);
+ ClassDB::set_method_flags(get_class_static(), _scs_create("lightmap_unwrap"), METHOD_FLAGS_DEFAULT | METHOD_FLAG_EDITOR);
ClassDB::bind_method(D_METHOD("get_faces"), &ArrayMesh::get_faces);
ClassDB::bind_method(D_METHOD("generate_triangle_mesh"), &ArrayMesh::generate_triangle_mesh);
ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &ArrayMesh::set_custom_aabb);
ClassDB::bind_method(D_METHOD("get_custom_aabb"), &ArrayMesh::get_custom_aabb);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "blend_shape_mode", PROPERTY_HINT_ENUM, "Normalized,Relative", PROPERTY_USAGE_NOEDITOR), "set_blend_shape_mode", "get_blend_shape_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
+
BIND_CONSTANT(NO_INDEX_ARRAY);
BIND_CONSTANT(ARRAY_WEIGHTS_SIZE);
diff --git a/scene/resources/mesh.h b/scene/resources/mesh.h
index ea38ebf2ff..e8b7ecaf9a 100644
--- a/scene/resources/mesh.h
+++ b/scene/resources/mesh.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MESH_H
#define MESH_H
diff --git a/scene/resources/mesh_data_tool.cpp b/scene/resources/mesh_data_tool.cpp
index 116ddc4ac6..8639b325c3 100644
--- a/scene/resources/mesh_data_tool.cpp
+++ b/scene/resources/mesh_data_tool.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "mesh_data_tool.h"
void MeshDataTool::clear() {
diff --git a/scene/resources/mesh_data_tool.h b/scene/resources/mesh_data_tool.h
index 119b49161b..f614b80c3b 100644
--- a/scene/resources/mesh_data_tool.h
+++ b/scene/resources/mesh_data_tool.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MESH_DATA_TOOL_H
#define MESH_DATA_TOOL_H
diff --git a/scene/resources/mesh_library.cpp b/scene/resources/mesh_library.cpp
index 833a4c3d22..e1d3540fd1 100644
--- a/scene/resources/mesh_library.cpp
+++ b/scene/resources/mesh_library.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "mesh_library.h"
bool MeshLibrary::_set(const StringName &p_name, const Variant &p_value) {
diff --git a/scene/resources/mesh_library.h b/scene/resources/mesh_library.h
index c5d23ce50f..69719960e2 100644
--- a/scene/resources/mesh_library.h
+++ b/scene/resources/mesh_library.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef GRID_THEME_H
#define GRID_THEME_H
diff --git a/scene/resources/multimesh.cpp b/scene/resources/multimesh.cpp
index ee6efa6e85..4d0a14e3aa 100644
--- a/scene/resources/multimesh.cpp
+++ b/scene/resources/multimesh.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "multimesh.h"
#include "servers/visual_server.h"
@@ -210,8 +211,8 @@ void MultiMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "transform_format", PROPERTY_HINT_ENUM, "2D,3D"), "set_transform_format", "get_transform_format");
ADD_PROPERTY(PropertyInfo(Variant::INT, "instance_count", PROPERTY_HINT_RANGE, "0,16384,1"), "set_instance_count", "get_instance_count");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"), "set_mesh", "get_mesh");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_transform_array", "_get_transform_array");
- ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "color_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_color_array", "_get_color_array");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "transform_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_transform_array", "_get_transform_array");
+ ADD_PROPERTY(PropertyInfo(Variant::POOL_COLOR_ARRAY, "color_array", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_color_array", "_get_color_array");
BIND_ENUM_CONSTANT(TRANSFORM_2D);
BIND_ENUM_CONSTANT(TRANSFORM_3D);
diff --git a/scene/resources/multimesh.h b/scene/resources/multimesh.h
index 0a5310f641..0875d6d06d 100644
--- a/scene/resources/multimesh.h
+++ b/scene/resources/multimesh.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef MULTIMESH_H
#define MULTIMESH_H
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 3a5cb7da2e..846f6e356e 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "packed_scene.h"
#include "core/core_string_names.h"
@@ -234,6 +235,7 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (p_edit_state == GEN_EDIT_STATE_MAIN) {
//for the main scene, use the resource as is
res->configure_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = res;
} else {
//for instances, a copy must be made
@@ -243,13 +245,12 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
res = local_dupe;
value = local_dupe;
}
-
- //this here may reference nodes not iniialized so this line is commented and used after loading all nodes
- //res->setup_local_to_scene();
}
//must make a copy, because this res is local to scene
}
}
+ } else if (p_edit_state == GEN_EDIT_STATE_INSTANCE) {
+ value = value.duplicate(true); // Duplicate arrays and dictionaries for the editor
}
node->set(snames[nprops[j].name], value, &valid);
}
@@ -270,6 +271,8 @@ Node *SceneState::instance(GenEditState p_edit_state) const {
if (i > 0) {
if (parent) {
parent->_add_child_nocheck(node, snames[n.name]);
+ if (n.index >= 0 && n.index < parent->get_child_count() - 1)
+ parent->move_child(node, n.index);
} else {
//it may be possible that an instanced scene has changed
//and the node has nowhere to go anymore
@@ -386,6 +389,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Map
nd.name = _nm_get_string(p_node->get_name(), name_map);
nd.instance = -1; //not instanced by default
+ nd.index = p_node->get_index();
// if this node is part of an instanced scene or sub-instanced scene
// we need to get the corresponding instance states.
@@ -1114,7 +1118,10 @@ void SceneState::set_bundled_scene(const Dictionary &p_dictionary) {
nd.parent = r[idx++];
nd.owner = r[idx++];
nd.type = r[idx++];
- nd.name = r[idx++];
+ uint32_t name_index = r[idx++];
+ nd.name = name_index & ((1 << NAME_INDEX_BITS) - 1);
+ nd.index = (name_index >> NAME_INDEX_BITS);
+ nd.index--; //0 is invalid, stored as 1
nd.instance = r[idx++];
nd.properties.resize(r[idx++]);
for (int j = 0; j < nd.properties.size(); j++) {
@@ -1206,7 +1213,11 @@ Dictionary SceneState::get_bundled_scene() const {
rnodes.push_back(nd.parent);
rnodes.push_back(nd.owner);
rnodes.push_back(nd.type);
- rnodes.push_back(nd.name);
+ uint32_t name_index = nd.name;
+ if (nd.index < (1 << (32 - NAME_INDEX_BITS)) - 1) { //save if less than 16k children
+ name_index |= uint32_t(nd.index + 1) << NAME_INDEX_BITS; //for backwards compatibility, index 0 is no index
+ }
+ rnodes.push_back(name_index);
rnodes.push_back(nd.instance);
rnodes.push_back(nd.properties.size());
for (int j = 0; j < nd.properties.size(); j++) {
@@ -1284,6 +1295,11 @@ StringName SceneState::get_node_name(int p_idx) const {
return names[nodes[p_idx].name];
}
+int SceneState::get_node_index(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, nodes.size(), -1);
+ return nodes[p_idx].index;
+}
+
bool SceneState::is_node_instance_placeholder(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, nodes.size(), false);
@@ -1524,7 +1540,7 @@ int SceneState::add_node_path(const NodePath &p_path) {
node_paths.push_back(p_path);
return (node_paths.size() - 1) | FLAG_ID_IS_PATH;
}
-int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance) {
+int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index) {
NodeData nd;
nd.parent = p_parent;
@@ -1532,6 +1548,7 @@ int SceneState::add_node(int p_parent, int p_owner, int p_type, int p_name, int
nd.type = p_type;
nd.name = p_name;
nd.instance = p_instance;
+ nd.index = p_index;
nodes.push_back(nd);
@@ -1605,6 +1622,7 @@ void SceneState::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_instance_placeholder", "idx"), &SceneState::get_node_instance_placeholder);
ClassDB::bind_method(D_METHOD("get_node_instance", "idx"), &SceneState::get_node_instance);
ClassDB::bind_method(D_METHOD("get_node_groups", "idx"), &SceneState::_get_node_groups);
+ ClassDB::bind_method(D_METHOD("get_node_index", "idx"), &SceneState::get_node_index);
ClassDB::bind_method(D_METHOD("get_node_property_count", "idx"), &SceneState::get_node_property_count);
ClassDB::bind_method(D_METHOD("get_node_property_name", "idx", "prop_idx"), &SceneState::get_node_property_name);
ClassDB::bind_method(D_METHOD("get_node_property_value", "idx", "prop_idx"), &SceneState::get_node_property_value);
diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h
index 20bfb19b1f..278986eb62 100644
--- a/scene/resources/packed_scene.h
+++ b/scene/resources/packed_scene.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PACKED_SCENE_H
#define PACKED_SCENE_H
@@ -48,6 +49,8 @@ class SceneState : public Reference {
enum {
NO_PARENT_SAVED = 0x7FFFFFFF,
+ NAME_INDEX_BITS = 18,
+ NAME_MASK = (1 << NAME_INDEX_BITS) - 1,
};
struct NodeData {
@@ -57,6 +60,7 @@ class SceneState : public Reference {
int type;
int name;
int instance;
+ int index;
struct Property {
@@ -151,6 +155,7 @@ public:
String get_node_instance_placeholder(int p_idx) const;
bool is_node_instance_placeholder(int p_idx) const;
Vector<StringName> get_node_groups(int p_idx) const;
+ int get_node_index(int p_idx) const;
int get_node_property_count(int p_idx) const;
StringName get_node_property_name(int p_idx, int p_prop) const;
@@ -174,7 +179,7 @@ public:
int find_name(const StringName &p_name) const;
int add_value(const Variant &p_value);
int add_node_path(const NodePath &p_path);
- int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance);
+ int add_node(int p_parent, int p_owner, int p_type, int p_name, int p_instance, int p_index);
void add_node_property(int p_node, int p_name, int p_value);
void add_node_group(int p_node, int p_group);
void set_base_scene(int p_idx);
diff --git a/scene/resources/plane_shape.cpp b/scene/resources/plane_shape.cpp
index 2eb2ceff24..4d38ebe090 100644
--- a/scene/resources/plane_shape.cpp
+++ b/scene/resources/plane_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "plane_shape.h"
#include "servers/physics_server.h"
diff --git a/scene/resources/plane_shape.h b/scene/resources/plane_shape.h
index 1384b7521b..c24c9474fb 100644
--- a/scene/resources/plane_shape.h
+++ b/scene/resources/plane_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef PLANE_SHAPE_H
#define PLANE_SHAPE_H
diff --git a/scene/resources/polygon_path_finder.cpp b/scene/resources/polygon_path_finder.cpp
index 053369e8d8..6fea2e1a8e 100644
--- a/scene/resources/polygon_path_finder.cpp
+++ b/scene/resources/polygon_path_finder.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "polygon_path_finder.h"
#include "geometry.h"
@@ -588,7 +589,7 @@ void PolygonPathFinder::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data"), &PolygonPathFinder::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &PolygonPathFinder::_get_data);
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
PolygonPathFinder::PolygonPathFinder() {
diff --git a/scene/resources/polygon_path_finder.h b/scene/resources/polygon_path_finder.h
index 9b760caa2e..19761c274c 100644
--- a/scene/resources/polygon_path_finder.h
+++ b/scene/resources/polygon_path_finder.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef POLYGON_PATH_FINDER_H
#define POLYGON_PATH_FINDER_H
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 2e8f9cbb33..5b600623b9 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -57,6 +57,31 @@ void PrimitiveMesh::_update() const {
}
}
+ if (flip_faces) {
+ PoolVector<Vector3> normals = arr[VS::ARRAY_NORMAL];
+ PoolVector<int> indices = arr[VS::ARRAY_INDEX];
+ if (normals.size() && indices.size()) {
+
+ {
+ int nc = normals.size();
+ PoolVector<Vector3>::Write w = normals.write();
+ for (int i = 0; i < nc; i++) {
+ w[i] = -w[i];
+ }
+ }
+
+ {
+ int ic = indices.size();
+ PoolVector<int>::Write w = indices.write();
+ for (int i = 0; i < ic; i += 3) {
+ SWAP(w[i + 0], w[i + 1]);
+ }
+ }
+ arr[VS::ARRAY_NORMAL] = normals;
+ arr[VS::ARRAY_INDEX] = indices;
+ }
+ }
+
// in with the new
VisualServer::get_singleton()->mesh_clear(mesh);
VisualServer::get_singleton()->mesh_add_surface_from_arrays(mesh, (VisualServer::PrimitiveType)primitive_type, arr);
@@ -65,6 +90,8 @@ void PrimitiveMesh::_update() const {
pending_request = false;
_clear_triangle_mesh();
+
+ const_cast<PrimitiveMesh *>(this)->emit_changed();
}
void PrimitiveMesh::_request_update() {
@@ -164,7 +191,15 @@ void PrimitiveMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh_arrays"), &PrimitiveMesh::get_mesh_arrays);
+ ClassDB::bind_method(D_METHOD("set_custom_aabb", "aabb"), &PrimitiveMesh::set_custom_aabb);
+ ClassDB::bind_method(D_METHOD("get_custom_aabb"), &PrimitiveMesh::get_custom_aabb);
+
+ ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &PrimitiveMesh::set_flip_faces);
+ ClassDB::bind_method(D_METHOD("get_flip_faces"), &PrimitiveMesh::get_flip_faces);
+
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SpatialMaterial,ShaderMaterial"), "set_material", "get_material");
+ ADD_PROPERTY(PropertyInfo(Variant::AABB, "custom_aabb", PROPERTY_HINT_NONE, ""), "set_custom_aabb", "get_custom_aabb");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
}
void PrimitiveMesh::set_material(const Ref<Material> &p_material) {
@@ -185,7 +220,30 @@ Array PrimitiveMesh::get_mesh_arrays() const {
return surface_get_arrays(0);
}
+void PrimitiveMesh::set_custom_aabb(const AABB &p_custom) {
+
+ custom_aabb = p_custom;
+ VS::get_singleton()->mesh_set_custom_aabb(mesh, custom_aabb);
+ emit_changed();
+}
+
+AABB PrimitiveMesh::get_custom_aabb() const {
+
+ return custom_aabb;
+}
+
+void PrimitiveMesh::set_flip_faces(bool p_enable) {
+ flip_faces = p_enable;
+ _request_update();
+}
+
+bool PrimitiveMesh::get_flip_faces() const {
+ return flip_faces;
+}
+
PrimitiveMesh::PrimitiveMesh() {
+
+ flip_faces = false;
// defaults
mesh = VisualServer::get_singleton()->mesh_create();
@@ -361,8 +419,8 @@ void CapsuleMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CapsuleMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CapsuleMesh::get_rings);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_mid_height", "get_mid_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "mid_height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_mid_height", "get_mid_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings");
}
@@ -618,7 +676,7 @@ void CubeMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth);
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth");
@@ -823,9 +881,9 @@ void CylinderMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_rings", "rings"), &CylinderMesh::set_rings);
ClassDB::bind_method(D_METHOD("get_rings"), &CylinderMesh::get_rings);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_top_radius", "get_top_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_bottom_radius", "get_bottom_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "top_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_top_radius", "get_top_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "bottom_radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_bottom_radius", "get_bottom_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings");
}
@@ -1224,7 +1282,7 @@ void PrismMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &PrismMesh::get_subdivide_depth);
ADD_PROPERTY(PropertyInfo(Variant::REAL, "left_to_right", PROPERTY_HINT_RANGE, "-2.0,2.0,0.1"), "set_left_to_right", "get_left_to_right");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_size", "get_size");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_height", "get_subdivide_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth");
@@ -1441,8 +1499,8 @@ void SphereMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_is_hemisphere", "is_hemisphere"), &SphereMesh::set_is_hemisphere);
ClassDB::bind_method(D_METHOD("get_is_hemisphere"), &SphereMesh::get_is_hemisphere);
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_radius", "get_radius");
- ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.1,100.0,0.1"), "set_height", "get_height");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_radius", "get_radius");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "height", PROPERTY_HINT_RANGE, "0.001,100.0,0.001"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::INT, "radial_segments", PROPERTY_HINT_RANGE, "1,100,1"), "set_radial_segments", "get_radial_segments");
ADD_PROPERTY(PropertyInfo(Variant::INT, "rings", PROPERTY_HINT_RANGE, "1,100,1"), "set_rings", "get_rings");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "is_hemisphere"), "set_is_hemisphere", "get_is_hemisphere");
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index b38c247827..a91aa09ffe 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,7 +39,7 @@
@author Bastiaan Olij <mux213@gmail.com>
Base class for all the classes in this file, handles a number of code functions that are shared among all meshes.
- This class is set appart that it assumes a single surface is always generated for our mesh.
+ This class is set apart that it assumes a single surface is always generated for our mesh.
*/
class PrimitiveMesh : public Mesh {
@@ -48,8 +48,10 @@ class PrimitiveMesh : public Mesh {
private:
RID mesh;
mutable AABB aabb;
+ AABB custom_aabb;
Ref<Material> material;
+ bool flip_faces;
mutable bool pending_request;
void _update() const;
@@ -81,6 +83,12 @@ public:
Array get_mesh_arrays() const;
+ void set_custom_aabb(const AABB &p_custom);
+ AABB get_custom_aabb() const;
+
+ void set_flip_faces(bool p_enable);
+ bool get_flip_faces() const;
+
PrimitiveMesh();
~PrimitiveMesh();
};
@@ -189,7 +197,7 @@ public:
};
/**
- Similar to quadmesh but with tesselation support
+ Similar to quadmesh but with tessellation support
*/
class PlaneMesh : public PrimitiveMesh {
diff --git a/scene/resources/ray_shape.cpp b/scene/resources/ray_shape.cpp
index b03a81b6bd..a9dec3e87c 100644
--- a/scene/resources/ray_shape.cpp
+++ b/scene/resources/ray_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "ray_shape.h"
#include "servers/physics_server.h"
@@ -42,7 +43,10 @@ Vector<Vector3> RayShape::_gen_debug_mesh_lines() {
void RayShape::_update_shape() {
- PhysicsServer::get_singleton()->shape_set_data(get_shape(), length);
+ Dictionary d;
+ d["length"] = length;
+ d["slips_on_slope"] = slips_on_slope;
+ PhysicsServer::get_singleton()->shape_set_data(get_shape(), d);
emit_changed();
}
@@ -51,6 +55,7 @@ void RayShape::set_length(float p_length) {
length = p_length;
_update_shape();
notify_change_to_owners();
+ _change_notify("length");
}
float RayShape::get_length() const {
@@ -58,16 +63,33 @@ float RayShape::get_length() const {
return length;
}
+void RayShape::set_slips_on_slope(bool p_active) {
+
+ slips_on_slope = p_active;
+ _update_shape();
+ notify_change_to_owners();
+ _change_notify("slips_on_slope");
+}
+
+bool RayShape::get_slips_on_slope() const {
+ return slips_on_slope;
+}
+
void RayShape::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &RayShape::get_length);
+ ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape::set_slips_on_slope);
+ ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape::get_slips_on_slope);
+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length", PROPERTY_HINT_RANGE, "0,4096,0.01"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
}
RayShape::RayShape() :
Shape(PhysicsServer::get_singleton()->shape_create(PhysicsServer::SHAPE_RAY)) {
set_length(1.0);
+ set_slips_on_slope(false);
}
diff --git a/scene/resources/ray_shape.h b/scene/resources/ray_shape.h
index 06b68adbae..f11b2e7c3c 100644
--- a/scene/resources/ray_shape.h
+++ b/scene/resources/ray_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RAY_SHAPE_H
#define RAY_SHAPE_H
#include "scene/resources/shape.h"
@@ -35,6 +36,7 @@ class RayShape : public Shape {
GDCLASS(RayShape, Shape);
float length;
+ bool slips_on_slope;
protected:
static void _bind_methods();
@@ -45,6 +47,9 @@ public:
void set_length(float p_length);
float get_length() const;
+ void set_slips_on_slope(bool p_active);
+ bool get_slips_on_slope() const;
+
RayShape();
};
#endif // RAY_SHAPE_H
diff --git a/scene/resources/rectangle_shape_2d.cpp b/scene/resources/rectangle_shape_2d.cpp
index 202024aa96..aeb22f6d0a 100644
--- a/scene/resources/rectangle_shape_2d.cpp
+++ b/scene/resources/rectangle_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "rectangle_shape_2d.h"
#include "servers/physics_2d_server.h"
diff --git a/scene/resources/rectangle_shape_2d.h b/scene/resources/rectangle_shape_2d.h
index 81d9cb1f4a..2d66d328fd 100644
--- a/scene/resources/rectangle_shape_2d.h
+++ b/scene/resources/rectangle_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef RECTANGLE_SHAPE_2D_H
#define RECTANGLE_SHAPE_2D_H
diff --git a/scene/resources/room.cpp b/scene/resources/room.cpp
index 487975dd4e..9493f8fbe6 100644
--- a/scene/resources/room.cpp
+++ b/scene/resources/room.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "room.h"
#include "servers/visual_server.h"
diff --git a/scene/resources/room.h b/scene/resources/room.h
index aadee858c2..359d918665 100644
--- a/scene/resources/room.h
+++ b/scene/resources/room.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef ROOM_BOUNDS_H
#define ROOM_BOUNDS_H
@@ -36,7 +37,7 @@
@author Juan Linietsky <reduzio@gmail.com>
*/
-//left for reference but will be removed when portals are reimplemented using Area
+// FIXME: left for reference but will be removed when portals are reimplemented using Area
#if 0
class RoomBounds : public Resource {
diff --git a/scene/resources/scene_format_text.cpp b/scene/resources/scene_format_text.cpp
index aebbb5b562..597866eb74 100644
--- a/scene/resources/scene_format_text.cpp
+++ b/scene/resources/scene_format_text.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* 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_text.h"
#include "core/io/resource_format_binary.h"
#include "os/dir_access.h"
@@ -198,6 +199,7 @@ Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R
int type = -1;
int name = -1;
int instance = -1;
+ int index = -1;
//int base_scene=-1;
if (next_tag.fields.has("name")) {
@@ -249,7 +251,11 @@ Ref<PackedScene> ResourceInteractiveLoaderText::_parse_node_tag(VariantParser::R
owner = 0; //if no owner, owner is root
}
- int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance);
+ if (next_tag.fields.has("index")) {
+ index = next_tag.fields["index"];
+ }
+
+ int node_id = packed_scene->get_state()->add_node(parent, owner, type, name, instance, index);
if (next_tag.fields.has("groups")) {
@@ -1306,6 +1312,8 @@ Error ResourceFormatLoaderText::rename_dependencies(const String &p_path, const
return ria->rename_dependencies(f, p_path, p_map);
}
+ResourceFormatLoaderText *ResourceFormatLoaderText::singleton = NULL;
+
Error ResourceFormatLoaderText::convert_file_to_binary(const String &p_src_path, const String &p_dst_path) {
Error err;
@@ -1405,7 +1413,7 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
I = I->next();
}
- resource_set.insert(res); //saved after, so the childs it needs are available when loaded
+ resource_set.insert(res); //saved after, so the children it needs are available when loaded
saved_resources.push_back(res);
} break;
@@ -1437,8 +1445,15 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
static String _valprop(const String &p_name) {
- if (p_name.find("\"") != -1 || p_name.find("=") != -1 || p_name.find(" ") != -1)
- return "\"" + p_name.c_escape_multiline() + "\"";
+ // Escape and quote strings with extended ASCII or further Unicode characters
+ // as well as '"', '=' or ' ' (32)
+ const CharType *cstr = p_name.c_str();
+ for (int i = 0; cstr[i]; i++) {
+ if (cstr[i] == '=' || cstr[i] == '"' || cstr[i] < 33 || cstr[i] > 126) {
+ return "\"" + p_name.c_escape_multiline() + "\"";
+ }
+ }
+ // Keep as is
return p_name;
}
@@ -1498,7 +1513,6 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
title += "load_steps=" + itos(load_steps) + " ";
}
title += "format=" + itos(FORMAT_VERSION) + "";
- //title+="engine_version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\"";
f->store_string(title);
f->store_line("]\n"); //one empty line
@@ -1609,6 +1623,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
StringName type = state->get_node_type(i);
StringName name = state->get_node_name(i);
+ int index = state->get_node_index(i);
NodePath path = state->get_node_path(i, true);
NodePath owner = state->get_node_owner_path(i);
Ref<PackedScene> instance = state->get_node_instance(i);
@@ -1626,6 +1641,9 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
if (owner != NodePath() && owner != NodePath(".")) {
header += " owner=\"" + String(owner.simplified()) + "\"";
}
+ if (index >= 0) {
+ header += " index=\"" + itos(index) + "\"";
+ }
if (groups.size()) {
String sgroups = " groups=[\n";
@@ -1654,7 +1672,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
f->store_string(vars);
}
- f->store_line("]\n");
+ f->store_line("]");
for (int j = 0; j < state->get_node_property_count(i); j++) {
@@ -1664,10 +1682,7 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
f->store_string(_valprop(String(state->get_node_property_name(i, j))) + " = " + vars + "\n");
}
- if (state->get_node_property_count(i)) {
- //add space
- f->store_line(String());
- }
+ f->store_line(String());
}
for (int i = 0; i < state->get_connection_count(); i++) {
@@ -1690,14 +1705,12 @@ Error ResourceFormatSaverTextInstance::save(const String &p_path, const RES &p_r
f->store_string(" binds= " + vars);
}
- f->store_line("]\n");
+ f->store_line("]");
}
- f->store_line(String());
-
Vector<NodePath> editable_instances = state->get_editable_instances();
for (int i = 0; i < editable_instances.size(); i++) {
- f->store_line("[editable path=\"" + editable_instances[i].operator String() + "\"]");
+ f->store_line("\n[editable path=\"" + editable_instances[i].operator String() + "\"]");
}
}
diff --git a/scene/resources/scene_format_text.h b/scene/resources/scene_format_text.h
index 5d3c2004c1..c28ded3d77 100644
--- a/scene/resources/scene_format_text.h
+++ b/scene/resources/scene_format_text.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* 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_TEXT_H
#define SCENE_FORMAT_TEXT_H
@@ -127,7 +128,9 @@ public:
};
class ResourceFormatLoaderText : public ResourceFormatLoader {
+
public:
+ static ResourceFormatLoaderText *singleton;
virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
virtual void get_recognized_extensions_for_type(const String &p_type, List<String> *p_extensions) const;
virtual void get_recognized_extensions(List<String> *p_extensions) const;
@@ -137,6 +140,8 @@ public:
virtual Error rename_dependencies(const String &p_path, const Map<String, String> &p_map);
static Error convert_file_to_binary(const String &p_src_path, const String &p_dst_path);
+
+ ResourceFormatLoaderText() { singleton = this; }
};
class ResourceFormatSaverTextInstance {
diff --git a/scene/resources/segment_shape_2d.cpp b/scene/resources/segment_shape_2d.cpp
index e8ef448e23..58027c127d 100644
--- a/scene/resources/segment_shape_2d.cpp
+++ b/scene/resources/segment_shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,11 +27,19 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "segment_shape_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+bool SegmentShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ Vector2 l[2] = { a, b };
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l);
+ return p_point.distance_to(closest) < p_tolerance;
+}
+
void SegmentShape2D::_update_shape() {
Rect2 r;
@@ -98,7 +106,10 @@ SegmentShape2D::SegmentShape2D() :
void RayShape2D::_update_shape() {
- Physics2DServer::get_singleton()->shape_set_data(get_rid(), length);
+ Dictionary d;
+ d["length"] = length;
+ d["slips_on_slope"] = slips_on_slope;
+ Physics2DServer::get_singleton()->shape_set_data(get_rid(), d);
emit_changed();
}
@@ -132,7 +143,11 @@ void RayShape2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_length", "length"), &RayShape2D::set_length);
ClassDB::bind_method(D_METHOD("get_length"), &RayShape2D::get_length);
+ ClassDB::bind_method(D_METHOD("set_slips_on_slope", "active"), &RayShape2D::set_slips_on_slope);
+ ClassDB::bind_method(D_METHOD("get_slips_on_slope"), &RayShape2D::get_slips_on_slope);
+
ADD_PROPERTY(PropertyInfo(Variant::REAL, "length"), "set_length", "get_length");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "slips_on_slope"), "set_slips_on_slope", "get_slips_on_slope");
}
void RayShape2D::set_length(real_t p_length) {
@@ -145,9 +160,20 @@ real_t RayShape2D::get_length() const {
return length;
}
+void RayShape2D::set_slips_on_slope(bool p_active) {
+
+ slips_on_slope = p_active;
+ _update_shape();
+}
+
+bool RayShape2D::get_slips_on_slope() const {
+ return slips_on_slope;
+}
+
RayShape2D::RayShape2D() :
Shape2D(Physics2DServer::get_singleton()->ray_shape_create()) {
length = 20;
+ slips_on_slope = false;
_update_shape();
}
diff --git a/scene/resources/segment_shape_2d.h b/scene/resources/segment_shape_2d.h
index eb9c228c83..700982ac0a 100644
--- a/scene/resources/segment_shape_2d.h
+++ b/scene/resources/segment_shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SEGMENT_SHAPE_2D_H
#define SEGMENT_SHAPE_2D_H
@@ -44,6 +45,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_a(const Vector2 &p_a);
void set_b(const Vector2 &p_b);
@@ -60,6 +63,7 @@ class RayShape2D : public Shape2D {
GDCLASS(RayShape2D, Shape2D);
real_t length;
+ bool slips_on_slope;
void _update_shape();
@@ -69,6 +73,10 @@ protected:
public:
void set_length(real_t p_length);
real_t get_length() const;
+
+ void set_slips_on_slope(bool p_active);
+ bool get_slips_on_slope() const;
+
virtual void draw(const RID &p_to_rid, const Color &p_color);
virtual Rect2 get_rect() const;
diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp
index 66df7dfda8..36740a307b 100644
--- a/scene/resources/shader.cpp
+++ b/scene/resources/shader.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "shader.h"
#include "os/file_access.h"
#include "scene/scene_string_names.h"
@@ -151,3 +152,80 @@ Shader::~Shader() {
VisualServer::get_singleton()->free(shader);
}
+////////////
+
+RES ResourceFormatLoaderShader::load(const String &p_path, const String &p_original_path, Error *r_error) {
+
+ if (r_error)
+ *r_error = ERR_FILE_CANT_OPEN;
+
+ Ref<Shader> shader;
+ shader.instance();
+
+ Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path);
+
+ String str;
+ str.parse_utf8((const char *)buffer.ptr(), buffer.size());
+
+ shader->set_code(str);
+
+ if (r_error)
+ *r_error = OK;
+
+ return shader;
+}
+
+void ResourceFormatLoaderShader::get_recognized_extensions(List<String> *p_extensions) const {
+
+ p_extensions->push_back("shader");
+}
+
+bool ResourceFormatLoaderShader::handles_type(const String &p_type) const {
+
+ return (p_type == "Shader");
+}
+
+String ResourceFormatLoaderShader::get_resource_type(const String &p_path) const {
+
+ String el = p_path.get_extension().to_lower();
+ if (el == "shader")
+ return "Shader";
+ return "";
+}
+
+Error ResourceFormatSaverShader::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+
+ Ref<Shader> shader = p_resource;
+ ERR_FAIL_COND_V(shader.is_null(), ERR_INVALID_PARAMETER);
+
+ String source = shader->get_code();
+
+ Error err;
+ FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+
+ if (err) {
+
+ ERR_FAIL_COND_V(err, err);
+ }
+
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ memdelete(file);
+ return ERR_CANT_CREATE;
+ }
+ file->close();
+ memdelete(file);
+
+ return OK;
+}
+
+void ResourceFormatSaverShader::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+
+ if (Object::cast_to<Shader>(*p_resource)) {
+ p_extensions->push_back("shader");
+ }
+}
+bool ResourceFormatSaverShader::recognize(const RES &p_resource) const {
+
+ return Object::cast_to<Shader>(*p_resource) != NULL;
+}
diff --git a/scene/resources/shader.h b/scene/resources/shader.h
index 5cc70629c7..248a6f0125 100644
--- a/scene/resources/shader.h
+++ b/scene/resources/shader.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,10 +27,12 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SHADER_H
#define SHADER_H
#include "io/resource_loader.h"
+#include "io/resource_saver.h"
#include "resource.h"
#include "scene/resources/texture.h"
@@ -38,7 +40,6 @@ class Shader : public Resource {
GDCLASS(Shader, Resource);
OBJ_SAVE_TYPE(Shader);
- RES_BASE_EXTENSION("shd");
public:
enum Mode {
@@ -95,4 +96,19 @@ public:
VARIANT_ENUM_CAST(Shader::Mode);
+class ResourceFormatLoaderShader : public ResourceFormatLoader {
+public:
+ virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = NULL);
+ virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual bool handles_type(const String &p_type) const;
+ virtual String get_resource_type(const String &p_path) const;
+};
+
+class ResourceFormatSaverShader : public ResourceFormatSaver {
+public:
+ virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const RES &p_resource) const;
+};
+
#endif // SHADER_H
diff --git a/scene/resources/shader_graph.cpp b/scene/resources/shader_graph.cpp
index 3813854922..070cc84863 100644
--- a/scene/resources/shader_graph.cpp
+++ b/scene/resources/shader_graph.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "shader_graph.h"
#include "scene/scene_string_names.h"
@@ -269,7 +270,7 @@ void ShaderGraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data"),&ShaderGraph::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"),&ShaderGraph::_get_data);
- ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR), "_set_data","_get_data");
+ ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_data",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data","_get_data");
//void get_connections(ShaderType p_which,List<Connection> *p_connections) const;
diff --git a/scene/resources/shader_graph.h b/scene/resources/shader_graph.h
index 5d9dd7054f..e3a68f8572 100644
--- a/scene/resources/shader_graph.h
+++ b/scene/resources/shader_graph.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SHADER_GRAPH_H
#define SHADER_GRAPH_H
diff --git a/scene/resources/shape.cpp b/scene/resources/shape.cpp
index 0046ff58a8..418d8ce819 100644
--- a/scene/resources/shape.cpp
+++ b/scene/resources/shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "shape.h"
#include "os/os.h"
diff --git a/scene/resources/shape.h b/scene/resources/shape.h
index bc75e723e9..ad87a69679 100644
--- a/scene/resources/shape.h
+++ b/scene/resources/shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SHAPE_H
#define SHAPE_H
diff --git a/scene/resources/shape_2d.cpp b/scene/resources/shape_2d.cpp
index 4423c78bbe..0ca518e5bb 100644
--- a/scene/resources/shape_2d.cpp
+++ b/scene/resources/shape_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "shape_2d.h"
#include "servers/physics_2d_server.h"
RID Shape2D::get_rid() const {
diff --git a/scene/resources/shape_2d.h b/scene/resources/shape_2d.h
index fffc7011f1..7eb0406bd8 100644
--- a/scene/resources/shape_2d.h
+++ b/scene/resources/shape_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SHAPE_2D_H
#define SHAPE_2D_H
@@ -44,6 +45,8 @@ protected:
Shape2D(const RID &p_rid);
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const { return get_rect().has_point(p_point); }
+
void set_custom_solver_bias(real_t p_bias);
real_t get_custom_solver_bias() const;
diff --git a/scene/resources/shape_line_2d.cpp b/scene/resources/shape_line_2d.cpp
index 512ff3bc56..1a81eea6e5 100644
--- a/scene/resources/shape_line_2d.cpp
+++ b/scene/resources/shape_line_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,9 +27,25 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "shape_line_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
+
+bool LineShape2D::_edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const {
+
+ Vector2 point = get_d() * get_normal();
+ Vector2 l[2][2] = { { point - get_normal().tangent() * 100, point + get_normal().tangent() * 100 }, { point, point + get_normal() * 30 } };
+
+ for (int i = 0; i < 2; i++) {
+ Vector2 closest = Geometry::get_closest_point_to_segment_2d(p_point, l[i]);
+ if (p_point.distance_to(closest) < p_tolerance)
+ return true;
+ }
+
+ return false;
+}
+
void LineShape2D::_update_shape() {
Array arr;
diff --git a/scene/resources/shape_line_2d.h b/scene/resources/shape_line_2d.h
index 68298b63be..7d31941558 100644
--- a/scene/resources/shape_line_2d.h
+++ b/scene/resources/shape_line_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SHAPE_LINE_2D_H
#define SHAPE_LINE_2D_H
@@ -44,6 +45,8 @@ protected:
static void _bind_methods();
public:
+ virtual bool _edit_is_selected_on_click(const Point2 &p_point, double p_tolerance) const;
+
void set_normal(const Vector2 &p_normal);
void set_d(real_t p_d);
diff --git a/scene/resources/sky_box.cpp b/scene/resources/sky_box.cpp
index a2c3f1f111..f2d5cb3516 100644
--- a/scene/resources/sky_box.cpp
+++ b/scene/resources/sky_box.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "sky_box.h"
#include "io/image_loader.h"
diff --git a/scene/resources/sky_box.h b/scene/resources/sky_box.h
index 8934463b6f..e561653a9e 100644
--- a/scene/resources/sky_box.h
+++ b/scene/resources/sky_box.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,8 +27,9 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef Sky_H
-#define Sky_H
+
+#ifndef SKY_BOX_H
+#define SKY_BOX_H
#include "os/thread.h"
#include "scene/resources/texture.h"
@@ -195,4 +196,4 @@ public:
VARIANT_ENUM_CAST(ProceduralSky::TextureSize)
-#endif // Sky_H
+#endif // SKY_BOX_H
diff --git a/scene/resources/space_2d.cpp b/scene/resources/space_2d.cpp
index 4177364de7..062f4099db 100644
--- a/scene/resources/space_2d.cpp
+++ b/scene/resources/space_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "space_2d.h"
RID Space2D::get_rid() const {
diff --git a/scene/resources/space_2d.h b/scene/resources/space_2d.h
index 8ba392f85d..148285ac6d 100644
--- a/scene/resources/space_2d.h
+++ b/scene/resources/space_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPACE_2D_H
#define SPACE_2D_H
diff --git a/scene/resources/sphere_shape.cpp b/scene/resources/sphere_shape.cpp
index 042988dcd3..d8ca1cf3f1 100644
--- a/scene/resources/sphere_shape.cpp
+++ b/scene/resources/sphere_shape.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "sphere_shape.h"
#include "servers/physics_server.h"
diff --git a/scene/resources/sphere_shape.h b/scene/resources/sphere_shape.h
index 43d7956246..5dd7daabc5 100644
--- a/scene/resources/sphere_shape.h
+++ b/scene/resources/sphere_shape.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SPHERE_SHAPE_H
#define SPHERE_SHAPE_H
diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp
index f4a9abc1ea..ebad00b068 100644
--- a/scene/resources/style_box.cpp
+++ b/scene/resources/style_box.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "style_box.h"
#include <limits.h>
@@ -100,23 +101,27 @@ StyleBox::StyleBox() {
}
}
-void StyleBoxTexture::set_texture(RES p_texture) {
+void StyleBoxTexture::set_texture(Ref<Texture> p_texture) {
if (texture == p_texture)
return;
texture = p_texture;
- region_rect = Rect2(Point2(), texture->get_size());
+ if (p_texture.is_null()) {
+ region_rect = Rect2(0, 0, 0, 0);
+ } else {
+ region_rect = Rect2(Point2(), texture->get_size());
+ }
emit_signal("texture_changed");
emit_changed();
_change_notify("texture");
}
-RES StyleBoxTexture::get_texture() const {
+Ref<Texture> StyleBoxTexture::get_texture() const {
return texture;
}
-void StyleBoxTexture::set_normal_map(RES p_normal_map) {
+void StyleBoxTexture::set_normal_map(Ref<Texture> p_normal_map) {
if (normal_map == p_normal_map)
return;
@@ -124,15 +129,24 @@ void StyleBoxTexture::set_normal_map(RES p_normal_map) {
emit_changed();
}
-RES StyleBoxTexture::get_normal_map() const {
+Ref<Texture> StyleBoxTexture::get_normal_map() const {
return normal_map;
}
void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) {
+ ERR_FAIL_INDEX(p_margin, 4);
+
margin[p_margin] = p_size;
emit_changed();
+ static const char *margin_prop[4] = {
+ "content_margin_left",
+ "content_margin_top",
+ "content_margin_right",
+ "content_margin_bottom",
+ };
+ _change_notify(margin_prop[p_margin]);
}
float StyleBoxTexture::get_margin_size(Margin p_margin) const {
@@ -181,7 +195,7 @@ Size2 StyleBoxTexture::get_center_size() const {
if (texture.is_null())
return Size2();
- return texture->get_size() - get_minimum_size();
+ return region_rect.size - get_minimum_size();
}
void StyleBoxTexture::set_expand_margin_size(Margin p_expand_margin, float p_size) {
@@ -649,14 +663,14 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
style_rect = style_rect.grow(-((aa_size + 1) / 2));
}
- //adapt borders (prevent weired overlapping/glitchy drawings)
- int width = style_rect.size.width;
- int height = style_rect.size.height;
+ //adapt borders (prevent weird overlapping/glitchy drawings)
+ int width = MAX(style_rect.size.width, 0);
+ int height = MAX(style_rect.size.height, 0);
int adapted_border[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
adapt_values(MARGIN_TOP, MARGIN_BOTTOM, adapted_border, border_width, height, height, height);
adapt_values(MARGIN_LEFT, MARGIN_RIGHT, adapted_border, border_width, width, width, width);
- //adapt corners (prevent weired overlapping/glitchy drawings)
+ //adapt corners (prevent weird overlapping/glitchy drawings)
int adapted_corner[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]);
adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]);
@@ -911,6 +925,7 @@ void StyleBoxLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_vertical"), &StyleBoxLine::is_vertical);
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "grow", PROPERTY_HINT_RANGE, "-300,300,1"), "set_grow", "get_grow");
ADD_PROPERTY(PropertyInfo(Variant::INT, "thickness", PROPERTY_HINT_RANGE, "0,10"), "set_thickness", "get_thickness");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
}
diff --git a/scene/resources/style_box.h b/scene/resources/style_box.h
index 4627c900ff..c1d84fe19f 100644
--- a/scene/resources/style_box.h
+++ b/scene/resources/style_box.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef STYLE_BOX_H
#define STYLE_BOX_H
@@ -111,11 +112,11 @@ public:
void set_region_rect(const Rect2 &p_region_rect);
Rect2 get_region_rect() const;
- void set_texture(RES p_texture);
- RES get_texture() const;
+ void set_texture(Ref<Texture> p_texture);
+ Ref<Texture> get_texture() const;
- void set_normal_map(RES p_normal_map);
- RES get_normal_map() const;
+ void set_normal_map(Ref<Texture> p_normal_map);
+ Ref<Texture> get_normal_map() const;
void set_draw_center(bool p_enabled);
bool is_draw_center_enabled() const;
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index d8600e041d..5a42873d79 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "surface_tool.h"
#include "method_bind_ext.gen.inc"
@@ -860,7 +861,7 @@ void SurfaceTool::generate_tangents() {
}
}
-void SurfaceTool::generate_normals() {
+void SurfaceTool::generate_normals(bool p_flip) {
ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES);
@@ -886,7 +887,11 @@ void SurfaceTool::generate_normals() {
ERR_FAIL_COND(!v[2]);
E = v[2]->next();
- Vector3 normal = Plane(v[0]->get().vertex, v[1]->get().vertex, v[2]->get().vertex).normal;
+ Vector3 normal;
+ if (!p_flip)
+ normal = Plane(v[0]->get().vertex, v[1]->get().vertex, v[2]->get().vertex).normal;
+ else
+ normal = Plane(v[2]->get().vertex, v[1]->get().vertex, v[0]->get().vertex).normal;
if (smooth) {
@@ -979,7 +984,7 @@ void SurfaceTool::_bind_methods() {
ClassDB::bind_method(D_METHOD("index"), &SurfaceTool::index);
ClassDB::bind_method(D_METHOD("deindex"), &SurfaceTool::deindex);
- ClassDB::bind_method(D_METHOD("generate_normals"), &SurfaceTool::generate_normals);
+ ClassDB::bind_method(D_METHOD("generate_normals", "flip"), &SurfaceTool::generate_normals, DEFVAL(false));
ClassDB::bind_method(D_METHOD("generate_tangents"), &SurfaceTool::generate_tangents);
ClassDB::bind_method(D_METHOD("add_to_format", "flags"), &SurfaceTool::add_to_format);
diff --git a/scene/resources/surface_tool.h b/scene/resources/surface_tool.h
index b180ffe260..459d399380 100644
--- a/scene/resources/surface_tool.h
+++ b/scene/resources/surface_tool.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SURFACE_TOOL_H
#define SURFACE_TOOL_H
@@ -115,7 +116,7 @@ public:
void index();
void deindex();
- void generate_normals();
+ void generate_normals(bool p_flip = false);
void generate_tangents();
void add_to_format(int p_flags) { format |= p_flags; }
diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp
index 987d6c5f6a..54f5aea160 100644
--- a/scene/resources/texture.cpp
+++ b/scene/resources/texture.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "texture.h"
#include "core/method_bind_ext.gen.inc"
#include "core/os/os.h"
@@ -75,10 +76,14 @@ void Texture::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true));
ClassDB::bind_method(D_METHOD("get_data"), &Texture::get_data);
+ ADD_GROUP("Flags", "");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic Linear,Convert to Linear,Mirrored Repeat,Video Surface"), "set_flags", "get_flags");
+ ADD_GROUP("", "");
+
+ BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
BIND_ENUM_CONSTANT(FLAG_MIPMAPS);
BIND_ENUM_CONSTANT(FLAG_REPEAT);
BIND_ENUM_CONSTANT(FLAG_FILTER);
- BIND_ENUM_CONSTANT(FLAGS_DEFAULT);
BIND_ENUM_CONSTANT(FLAG_ANISOTROPIC_FILTER);
BIND_ENUM_CONSTANT(FLAG_CONVERT_TO_LINEAR);
BIND_ENUM_CONSTANT(FLAG_MIRRORED_REPEAT);
@@ -120,10 +125,6 @@ bool ImageTexture::_set(const StringName &p_name, const Variant &p_value) {
w = s.width;
h = s.height;
VisualServer::get_singleton()->texture_set_size_override(texture, w, h);
- } else if (p_name == "storage") {
- storage = Storage(p_value.operator int());
- } else if (p_name == "lossy_quality") {
- lossy_storage_quality = p_value;
} else if (p_name == "_data") {
_set_data(p_value);
} else
@@ -142,10 +143,6 @@ bool ImageTexture::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = flags;
else if (p_name == "size")
r_ret = Size2(w, h);
- else if (p_name == "storage")
- r_ret = storage;
- else if (p_name == "lossy_quality")
- r_ret = lossy_storage_quality;
else
return false;
@@ -164,8 +161,6 @@ void ImageTexture::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic,sRGB,Mirrored Repeat"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "image", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
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"));
- p_list->push_back(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"));
}
void ImageTexture::_reload_hook(const RID &p_hook) {
@@ -227,12 +222,15 @@ Image::Format ImageTexture::get_format() const {
return format;
}
-void ImageTexture::load(const String &p_path) {
+Error ImageTexture::load(const String &p_path) {
Ref<Image> img;
img.instance();
- img->load(p_path);
- create_from_image(img);
+ Error err = img->load(p_path);
+ if (err == OK) {
+ create_from_image(img);
+ }
+ return err;
}
void ImageTexture::set_data(const Ref<Image> &p_image) {
@@ -362,6 +360,9 @@ void ImageTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_size_override", "size"), &ImageTexture::set_size_override);
ClassDB::bind_method(D_METHOD("_reload_hook", "rid"), &ImageTexture::_reload_hook);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "storage", PROPERTY_HINT_ENUM, "Uncompressed,Compress Lossy,Compress Lossless"), "set_storage", "get_storage");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "lossy_quality", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_lossy_storage_quality", "get_lossy_storage_quality");
+
BIND_ENUM_CONSTANT(STORAGE_RAW);
BIND_ENUM_CONSTANT(STORAGE_COMPRESS_LOSSY);
BIND_ENUM_CONSTANT(STORAGE_COMPRESS_LOSSLESS);
@@ -707,6 +708,8 @@ Ref<Image> StreamTexture::get_data() const {
}
void StreamTexture::set_flags(uint32_t p_flags) {
+ flags = p_flags;
+ VS::get_singleton()->texture_set_flags(texture, flags);
}
void StreamTexture::reload_from_file() {
@@ -1130,7 +1133,7 @@ void LargeTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_data", "data"), &LargeTexture::_set_data);
ClassDB::bind_method(D_METHOD("_get_data"), &LargeTexture::_get_data);
- ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "_set_data", "_get_data");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
}
void LargeTexture::draw(RID p_canvas_item, const Point2 &p_pos, const Color &p_modulate, bool p_transpose, const Ref<Texture> &p_normal_map) const {
@@ -1281,8 +1284,6 @@ bool CubeMap::_set(const StringName &p_name, const Variant &p_value) {
set_side(SIDE_FRONT, p_value);
} else if (p_name == "side/back") {
set_side(SIDE_BACK, p_value);
- } else if (p_name == "flags") {
- set_flags(p_value);
} else if (p_name == "storage") {
storage = Storage(p_value.operator int());
} else if (p_name == "lossy_quality") {
@@ -1307,8 +1308,6 @@ bool CubeMap::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = get_side(SIDE_FRONT);
} else if (p_name == "side/back") {
r_ret = get_side(SIDE_BACK);
- } else if (p_name == "flags") {
- r_ret = flags;
} else if (p_name == "storage") {
r_ret = storage;
} else if (p_name == "lossy_quality") {
@@ -1328,7 +1327,6 @@ void CubeMap::_get_property_list(List<PropertyInfo> *p_list) const {
img_hint = PROPERTY_HINT_IMAGE_COMPRESS_LOSSLESS;
}
- p_list->push_back(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/left", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/right", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
p_list->push_back(PropertyInfo(Variant::OBJECT, "side/bottom", PROPERTY_HINT_RESOURCE_TYPE, "Image"));
@@ -1350,6 +1348,7 @@ void CubeMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_lossy_storage_quality", "quality"), &CubeMap::set_lossy_storage_quality);
ClassDB::bind_method(D_METHOD("get_lossy_storage_quality"), &CubeMap::get_lossy_storage_quality);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter"), "set_flags", "get_flags");
ADD_PROPERTY(PropertyInfo(Variant::INT, "storage_mode", PROPERTY_HINT_ENUM, "Raw,Lossy Compressed,Lossless Compressed"), "set_storage", "get_storage");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "lossy_storage_quality"), "set_lossy_storage_quality", "get_lossy_storage_quality");
diff --git a/scene/resources/texture.h b/scene/resources/texture.h
index 76c0195ef9..d81fd3b19b 100644
--- a/scene/resources/texture.h
+++ b/scene/resources/texture.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TEXTURE_H
#define TEXTURE_H
@@ -123,7 +124,7 @@ public:
void set_flags(uint32_t p_flags);
uint32_t get_flags() const;
Image::Format get_format() const;
- void load(const String &p_path);
+ Error load(const String &p_path);
void set_data(const Ref<Image> &p_image);
Ref<Image> get_data() const;
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index e2e29b037b..f903669fc7 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "theme.h"
#include "os/file_access.h"
#include "print_string.h"
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index 5b375d5585..c23f237c75 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef THEME_H
#define THEME_H
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index bd6b917d4e..58057cda0c 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "tile_set.h"
#include "array.h"
@@ -56,8 +57,8 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
tile_set_modulate(id, p_value);
else if (what == "region")
tile_set_region(id, p_value);
- else if (what == "is_autotile")
- tile_set_is_autotile(id, p_value);
+ else if (what == "tile_mode")
+ tile_set_tile_mode(id, (TileMode)((int)p_value));
else if (what.left(9) == "autotile/") {
what = what.right(9);
if (what == "bitmask_mode")
@@ -141,6 +142,8 @@ bool TileSet::_set(const StringName &p_name, const Variant &p_value) {
tile_set_navigation_polygon(id, p_value);
else if (what == "navigation_offset")
tile_set_navigation_polygon_offset(id, p_value);
+ else if (what == "z_index")
+ tile_set_z_index(id, p_value);
else
return false;
@@ -173,8 +176,8 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = tile_get_modulate(id);
else if (what == "region")
r_ret = tile_get_region(id);
- else if (what == "is_autotile")
- r_ret = tile_get_is_autotile(id);
+ else if (what == "tile_mode")
+ r_ret = tile_get_tile_mode(id);
else if (what.left(9) == "autotile/") {
what = what.right(9);
if (what == "bitmask_mode")
@@ -211,7 +214,7 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
Vector3 v;
for (Map<Vector2, int>::Element *E = tile_map[id].autotile_data.priority_map.front(); E; E = E->next()) {
if (E->value() > 1) {
- //Dont save default value
+ //Don't save default value
v.x = E->key().x;
v.y = E->key().y;
v.z = E->value();
@@ -238,6 +241,8 @@ bool TileSet::_get(const StringName &p_name, Variant &r_ret) const {
r_ret = tile_get_navigation_polygon(id);
else if (what == "navigation_offset")
r_ret = tile_get_navigation_polygon_offset(id);
+ else if (what == "z_index")
+ r_ret = tile_get_z_index(id);
else
return false;
@@ -257,16 +262,16 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "material", PROPERTY_HINT_RESOURCE_TYPE, "ShaderMaterial"));
p_list->push_back(PropertyInfo(Variant::COLOR, pre + "modulate"));
p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region"));
- p_list->push_back(PropertyInfo(Variant::BOOL, pre + "is_autotile", PROPERTY_HINT_NONE, ""));
- if (tile_get_is_autotile(id)) {
- p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
- p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE"));
+ if (tile_get_tile_mode(id) == AUTO_TILE) {
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/spacing", PROPERTY_HINT_RANGE, "0,256,1", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/occluder_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/navpoly_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/priority_map", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
}
p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "occluder_offset"));
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "occluder", PROPERTY_HINT_RESOURCE_TYPE, "OccluderPolygon2D"));
@@ -277,11 +282,11 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::OBJECT, pre + "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::BOOL, pre + "shape_one_way", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "shapes", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR));
+ p_list->push_back(PropertyInfo(Variant::INT, pre + "z_index", PROPERTY_HINT_RANGE, itos(VS::CANVAS_ITEM_Z_MIN) + "," + itos(VS::CANVAS_ITEM_Z_MAX) + ",1"));
}
}
void TileSet::create_tile(int p_id) {
-
ERR_FAIL_COND(tile_map.has(p_id));
tile_map[p_id] = TileData();
tile_map[p_id].autotile_data = AutotileData();
@@ -290,7 +295,6 @@ void TileSet::create_tile(int p_id) {
}
void TileSet::autotile_set_bitmask_mode(int p_id, BitmaskMode p_mode) {
-
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].autotile_data.bitmask_mode = p_mode;
_change_notify("");
@@ -308,6 +312,7 @@ void TileSet::tile_set_texture(int p_id, const Ref<Texture> &p_texture) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].texture = p_texture;
emit_changed();
+ _change_notify("texture");
}
Ref<Texture> TileSet::tile_get_texture(int p_id) const {
@@ -347,6 +352,7 @@ void TileSet::tile_set_modulate(int p_id, const Color &p_modulate) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].modulate = p_modulate;
emit_changed();
+ _change_notify("modulate");
}
Color TileSet::tile_get_modulate(int p_id) const {
@@ -373,6 +379,7 @@ void TileSet::tile_set_region(int p_id, const Rect2 &p_region) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].region = p_region;
emit_changed();
+ _change_notify("region");
}
Rect2 TileSet::tile_get_region(int p_id) const {
@@ -381,18 +388,17 @@ Rect2 TileSet::tile_get_region(int p_id) const {
return tile_map[p_id].region;
}
-void TileSet::tile_set_is_autotile(int p_id, bool p_is_autotile) {
-
+void TileSet::tile_set_tile_mode(int p_id, TileMode p_tile_mode) {
ERR_FAIL_COND(!tile_map.has(p_id));
- tile_map[p_id].is_autotile = p_is_autotile;
- _change_notify("");
+ tile_map[p_id].tile_mode = p_tile_mode;
emit_changed();
+ _change_notify("tile_mode");
}
-bool TileSet::tile_get_is_autotile(int p_id) const {
+TileSet::TileMode TileSet::tile_get_tile_mode(int p_id) const {
- ERR_FAIL_COND_V(!tile_map.has(p_id), false);
- return tile_map[p_id].is_autotile;
+ ERR_FAIL_COND_V(!tile_map.has(p_id), SINGLE_TILE);
+ return tile_map[p_id].tile_mode;
}
void TileSet::autotile_set_icon_coordinate(int p_id, Vector2 coord) {
@@ -532,6 +538,7 @@ void TileSet::tile_set_name(int p_id, const String &p_name) {
ERR_FAIL_COND(!tile_map.has(p_id));
tile_map[p_id].name = p_name;
emit_changed();
+ _change_notify("name");
}
String TileSet::tile_get_name(int p_id) const {
@@ -746,6 +753,19 @@ Vector<TileSet::ShapeData> TileSet::tile_get_shapes(int p_id) const {
return tile_map[p_id].shapes_data;
}
+int TileSet::tile_get_z_index(int p_id) const {
+
+ ERR_FAIL_COND_V(!tile_map.has(p_id), 0);
+ return tile_map[p_id].z_index;
+}
+
+void TileSet::tile_set_z_index(int p_id, int p_z_index) {
+
+ ERR_FAIL_COND(!tile_map.has(p_id));
+ tile_map[p_id].z_index = p_z_index;
+ emit_changed();
+}
+
void TileSet::_tile_set_shapes(int p_id, const Array &p_shapes) {
ERR_FAIL_COND(!tile_map.has(p_id));
@@ -893,8 +913,8 @@ void TileSet::clear() {
void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("create_tile", "id"), &TileSet::create_tile);
- ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "mode"), &TileSet::autotile_set_bitmask_mode);
- ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode"), &TileSet::autotile_get_bitmask_mode);
+ ClassDB::bind_method(D_METHOD("autotile_set_bitmask_mode", "id", "mode"), &TileSet::autotile_set_bitmask_mode);
+ ClassDB::bind_method(D_METHOD("autotile_get_bitmask_mode", "id"), &TileSet::autotile_get_bitmask_mode);
ClassDB::bind_method(D_METHOD("tile_set_name", "id", "name"), &TileSet::tile_set_name);
ClassDB::bind_method(D_METHOD("tile_get_name", "id"), &TileSet::tile_get_name);
ClassDB::bind_method(D_METHOD("tile_set_texture", "id", "texture"), &TileSet::tile_set_texture);
@@ -917,6 +937,8 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("tile_get_shape_count", "id"), &TileSet::tile_get_shape_count);
ClassDB::bind_method(D_METHOD("tile_set_shapes", "id", "shapes"), &TileSet::_tile_set_shapes);
ClassDB::bind_method(D_METHOD("tile_get_shapes", "id"), &TileSet::_tile_get_shapes);
+ ClassDB::bind_method(D_METHOD("tile_set_tile_mode", "id", "tilemode"), &TileSet::tile_set_tile_mode);
+ ClassDB::bind_method(D_METHOD("tile_get_tile_mode", "id"), &TileSet::tile_get_tile_mode);
ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon", "id", "navigation_polygon"), &TileSet::tile_set_navigation_polygon);
ClassDB::bind_method(D_METHOD("tile_get_navigation_polygon", "id"), &TileSet::tile_get_navigation_polygon);
ClassDB::bind_method(D_METHOD("tile_set_navigation_polygon_offset", "id", "navigation_polygon_offset"), &TileSet::tile_set_navigation_polygon_offset);
@@ -925,6 +947,8 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("tile_get_light_occluder", "id"), &TileSet::tile_get_light_occluder);
ClassDB::bind_method(D_METHOD("tile_set_occluder_offset", "id", "occluder_offset"), &TileSet::tile_set_occluder_offset);
ClassDB::bind_method(D_METHOD("tile_get_occluder_offset", "id"), &TileSet::tile_get_occluder_offset);
+ ClassDB::bind_method(D_METHOD("tile_set_z_index", "id", "z_index"), &TileSet::tile_set_z_index);
+ ClassDB::bind_method(D_METHOD("tile_get_z_index", "id"), &TileSet::tile_get_z_index);
ClassDB::bind_method(D_METHOD("remove_tile", "id"), &TileSet::remove_tile);
ClassDB::bind_method(D_METHOD("clear"), &TileSet::clear);
@@ -936,6 +960,7 @@ void TileSet::_bind_methods() {
BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location")));
BIND_ENUM_CONSTANT(BITMASK_2X2);
+ BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL);
BIND_ENUM_CONSTANT(BITMASK_3X3);
BIND_ENUM_CONSTANT(BIND_TOPLEFT);
@@ -946,6 +971,10 @@ void TileSet::_bind_methods() {
BIND_ENUM_CONSTANT(BIND_BOTTOMLEFT);
BIND_ENUM_CONSTANT(BIND_BOTTOM);
BIND_ENUM_CONSTANT(BIND_BOTTOMRIGHT);
+
+ BIND_ENUM_CONSTANT(SINGLE_TILE);
+ BIND_ENUM_CONSTANT(AUTO_TILE);
+ BIND_ENUM_CONSTANT(ANIMATED_TILE);
}
TileSet::TileSet() {
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index deac583f62..ec635ee5cc 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef TILE_SET_H
#define TILE_SET_H
@@ -55,6 +56,7 @@ public:
enum BitmaskMode {
BITMASK_2X2,
+ BITMASK_3X3_MINIMAL,
BITMASK_3X3
};
@@ -70,6 +72,12 @@ public:
BIND_BOTTOMRIGHT = 256
};
+ enum TileMode {
+ SINGLE_TILE,
+ AUTO_TILE,
+ ANIMATED_TILE
+ };
+
struct AutotileData {
BitmaskMode bitmask_mode;
int spacing;
@@ -83,6 +91,7 @@ public:
// Default size to prevent invalid value
explicit AutotileData() :
size(64, 64),
+ spacing(0),
icon_coord(0, 0) {
bitmask_mode = BITMASK_2X2;
}
@@ -103,13 +112,15 @@ private:
Ref<NavigationPolygon> navigation_polygon;
Ref<ShaderMaterial> material;
Color modulate;
- bool is_autotile;
+ TileMode tile_mode;
AutotileData autotile_data;
+ int z_index;
// Default modulate for back-compat
explicit TileData() :
+ tile_mode(SINGLE_TILE),
modulate(1, 1, 1),
- is_autotile(false) {}
+ z_index(0) {}
};
Map<int, TileData> tile_map;
@@ -145,8 +156,8 @@ public:
void tile_set_region(int p_id, const Rect2 &p_region);
Rect2 tile_get_region(int p_id) const;
- void tile_set_is_autotile(int p_id, bool p_is_autotile);
- bool tile_get_is_autotile(int p_id) const;
+ void tile_set_tile_mode(int p_id, TileMode p_tile_mode);
+ TileMode tile_get_tile_mode(int p_id) const;
void autotile_set_icon_coordinate(int p_id, Vector2 coord);
Vector2 autotile_get_icon_coordinate(int p_id) const;
@@ -212,6 +223,9 @@ public:
Ref<NavigationPolygon> autotile_get_navigation_polygon(int p_id, const Vector2 &p_coord) const;
const Map<Vector2, Ref<NavigationPolygon> > &autotile_get_navigation_map(int p_id) const;
+ void tile_set_z_index(int p_id, int p_z_index);
+ int tile_get_z_index(int p_id) const;
+
void remove_tile(int p_id);
bool has_tile(int p_id) const;
@@ -230,5 +244,6 @@ public:
VARIANT_ENUM_CAST(TileSet::AutotileBindings);
VARIANT_ENUM_CAST(TileSet::BitmaskMode);
+VARIANT_ENUM_CAST(TileSet::TileMode);
#endif // TILE_SET_H
diff --git a/scene/resources/video_stream.cpp b/scene/resources/video_stream.cpp
index 2298e2ca9f..3cd8cbae77 100644
--- a/scene/resources/video_stream.cpp
+++ b/scene/resources/video_stream.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "video_stream.h"
void VideoStreamPlayback::_bind_methods(){
diff --git a/scene/resources/video_stream.h b/scene/resources/video_stream.h
index fbe52909e7..0d25d9d687 100644
--- a/scene/resources/video_stream.h
+++ b/scene/resources/video_stream.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef VIDEO_STREAM_H
#define VIDEO_STREAM_H
diff --git a/scene/resources/world.cpp b/scene/resources/world.cpp
index c63ba24cbd..82183d24e7 100644
--- a/scene/resources/world.cpp
+++ b/scene/resources/world.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "world.h"
#include "camera_matrix.h"
@@ -317,6 +318,9 @@ void World::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World::get_direct_space_state);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_environment", "get_environment");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_environment", PROPERTY_HINT_RESOURCE_TYPE, "Environment"), "set_fallback_environment", "get_fallback_environment");
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space");
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "scenario", PROPERTY_HINT_NONE, "", 0), "", "get_scenario");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "PhysicsDirectSpaceState", 0), "", "get_direct_space_state");
}
World::World() {
diff --git a/scene/resources/world.h b/scene/resources/world.h
index e0f1de1fd0..54bdf25784 100644
--- a/scene/resources/world.h
+++ b/scene/resources/world.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef WORLD_H
#define WORLD_H
diff --git a/scene/resources/world_2d.cpp b/scene/resources/world_2d.cpp
index a644793bd8..bed6ffd1bd 100644
--- a/scene/resources/world_2d.cpp
+++ b/scene/resources/world_2d.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "world_2d.h"
#include "servers/physics_2d_server.h"
#include "servers/visual_server.h"
@@ -372,6 +373,10 @@ void World2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_space"), &World2D::get_space);
ClassDB::bind_method(D_METHOD("get_direct_space_state"), &World2D::get_direct_space_state);
+
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "canvas", PROPERTY_HINT_NONE, "", 0), "", "get_canvas");
+ ADD_PROPERTY(PropertyInfo(Variant::_RID, "space", PROPERTY_HINT_NONE, "", 0), "", "get_space");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "direct_space_state", PROPERTY_HINT_RESOURCE_TYPE, "Physics2DDirectSpaceState", 0), "", "get_direct_space_state");
}
Physics2DDirectSpaceState *World2D::get_direct_space_state() {
diff --git a/scene/resources/world_2d.h b/scene/resources/world_2d.h
index 63d32473e0..59f34e32f2 100644
--- a/scene/resources/world_2d.h
+++ b/scene/resources/world_2d.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef WORLD_2D_H
#define WORLD_2D_H
diff --git a/scene/scene_string_names.cpp b/scene/scene_string_names.cpp
index 52b8e35d5e..2dc32b893d 100644
--- a/scene/scene_string_names.cpp
+++ b/scene/scene_string_names.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#include "scene_string_names.h"
SceneStringNames *SceneStringNames::singleton = NULL;
@@ -48,7 +49,9 @@ SceneStringNames::SceneStringNames() {
shader_unshaded = StaticCString::create("shader/unshaded");
shading_mode = StaticCString::create("shader/shading_mode");
tree_entered = StaticCString::create("tree_entered");
+ tree_exiting = StaticCString::create("tree_exiting");
tree_exited = StaticCString::create("tree_exited");
+ ready = StaticCString::create("ready");
item_rect_changed = StaticCString::create("item_rect_changed");
size_flags_changed = StaticCString::create("size_flags_changed");
minimum_size_changed = StaticCString::create("minimum_size_changed");
diff --git a/scene/scene_string_names.h b/scene/scene_string_names.h
index 3b110e7a62..2e6da26d68 100644
--- a/scene/scene_string_names.h
+++ b/scene/scene_string_names.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -27,6 +27,7 @@
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+
#ifndef SCENE_STRING_NAMES_H
#define SCENE_STRING_NAMES_H
@@ -68,7 +69,9 @@ public:
StringName shader_unshaded;
StringName shading_mode;
StringName tree_entered;
+ StringName tree_exiting;
StringName tree_exited;
+ StringName ready;
StringName size_flags_changed;
StringName minimum_size_changed;
StringName sleeping_state_changed;